Skip to main content
Download the server examples. The archive includes three clients, runnable form integrations, and local tests under the MIT license. Copy the client into your backend; no registry installation is required. Keep the secret key and client on your server. Clients preserve the API response fields and validate its status fields. The plain HTML, Next.js, and SvelteKit guides include a complete form and protected write.

Verify a widget token

Here, attempt is your server’s saved pending action. Choose the hostname, site ID and policy in server configuration. Read token from the submitted heretic-response field.
HTTP 200 can contain success: false. With policy: "report", a verified proof can also carry a contradicted or refused verdict; evaluate it using your own rule. Siteverify defines each policy and error code.

Read a verdict

Use the request ID saved with your pending action. Check its site and age against that action before applying your signup rules.

Create and read a challenge

Take account_ref from your authenticated account record. Omit it for an anonymous ceremony. Save the returned challenge_id with the pending action before sending the URL to the browser.
A new challenge normally reads pending. Show its URL with heretic.challenge(). On completion, your backend reads the saved ID, requires status: "passed", and checks the saved account reference. A browser callback cannot authorize the write. See what a pass establishes. Challenge creation has no idempotency key. A timed-out mint may have created a challenge; the clients never retry it automatically.

Handle errors and retries

Clients make one request per call. Node and PHP default to a six-second request deadline; Python defaults to a six-second socket timeout. Configure Node with { timeoutMs: 3000 }, Python with timeout=3, or PHP with the third constructor argument 3000. Redirects are refused. HereticError exposes code in Node/Python or kind in PHP: http, network, timeout, or invalid-response. HTTP errors also carry status. A rate-limited response includes retryAfter in Node/PHP or retry_after in Python, plus codes where supplied. This is the server’s Retry-After header. Error messages omit credentials and response bodies. Keep the action pending on transport errors. Retry siteverify with the exact token, idempotency key, policy and expected context. Respect Retry-After on HTTP 429. An unavailable result cannot authorize the write. Write the action and consume its attempt in one database transaction. A repeated verification returns the existing action result. A challenge outcome remains readable, so its saved ID needs the same single-use treatment. The downloadable form examples implement this with a persistent SQLite receipt.