Siteverify endpoint
Exchange a challenge widget token for its result: verdict, whether a ceremony ran, and the assessment behind it.
POST
Siteverify endpoint
Call siteverify from your backend with the token the challenge widget wrote into the
The secret key travels in the body, not in a header.
heretic-response field. The request and the success / error-codes shape match Cloudflare Turnstile; the Heretic fields are added to the same object.
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 answerstimeout-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.Related topics
Challenge widgetQuickstartChallenge and usage endpointsHeretic documentationTenant verdict endpoint