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.
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
Takeaccount_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.
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.