Skip to main content
POST
Siteverify endpoint
Call siteverify from your backend with the token the challenge widget wrote into the heretic-response field. The request and the success / error-codes shape match Cloudflare Turnstile; the Heretic fields are added to the same object.
The secret key travels in the body, not in a header. application/x-www-form-urlencoded bodies are accepted with the same field names.

Request

Status codes

Every response carries cache-control: no-store.

Success response

boolean
required
true. The token was signed by Heretic, belongs to a site of the tenant that owns secret, has not expired, and has not been used before under a different key.
string
required
UTC RFC 3339 time the token was issued. Tokens expire 300 seconds after this time. It is not the time the ceremony completed.
string | null
required
Host of the page the widget ran on. For a real site key it matches the site’s verified domain, its www. form, or a subdomain of it, because the widget mints no token otherwise. For a test token it is the host the page claimed, unverified. Compare it with your own domain.
string | null
required
The widget’s data-action when the token was issued without a ceremony. null when a ceremony ran: the ceremony token does not carry the action.
string | null
required
The widget’s data-cdata, up to 255 characters. When a ceremony ran, the same value: it was recorded as the ceremony’s account_ref and is returned from there.
string | null
required
Raw 32-character request ID of the assessment behind the token. Read it with the same secret key at GET /v1/verdict/{request_id} for signals, families, network, concealment, identity, and the client record. null for a test token.
string
required
uncontradicted, contradicted, or refused. Which values reach you depends on the widget’s data-escalate policy: a verdict the policy steps up never arrives without challenged: true. See which values each path returns.
boolean
required
true when the visitor completed a device ceremony before the token was issued.
string | null
required
passed when challenged is true, else null. No token is issued for a ceremony that ended contradicted or not_completed, so no other value occurs.
boolean
true only when secret is the reserved test secret. Absent otherwise.

What each path returns

A probe whose result never reached Heretic is treated as refused for the escalation decision.

Single use and idempotency

A token verifies once. A second call with the same token answers timeout-or-duplicate, whichever secret key presents it. Send idempotency_key when your handler can run twice for one submission, for example after a retry. The second call succeeds only when it presents the same key as the first; the response is computed from the token, so it is identical. A first call without a key cannot be repeated with one. A different key is a replay. Consumed tokens are remembered until their 300-second expiry, and expiry alone also answers timeout-or-duplicate.

Failure response

error-codes carries exactly one code. Do not convert a failure into acceptance. A token Heretic cannot verify is no token.

Test secret

hrtc_sk_00000000000000000000000000000000 verifies only tokens minted by the always-pass test site key, answers with "test": true and request_id: null, and does not consume them. A real secret answers invalid-input-response to a test token. The keys are listed on the widget page.

Example

result.request_id is the handle for everything else Heretic measured. Policy on the verdict, the record, and the identifiers is yours.