Skip to content

Siteverify

Siteverify is the call your server makes to check a token the widget or app produced. It is the one step you must not skip: a token that was never verified proves nothing. If you are migrating from reCAPTCHA, it is a drop-in: the path /recaptcha/api/siteverify answers in the same shape.

Use siteverify for any form or action you protect: signup, login, checkout, comment, password reset. Use assessments instead when you want a richer answer (account labels, payment risk, annotations).

  1. The client obtains a response token (1 to 2048 characters of A-Z a-z 0-9 - _).
  2. The client sends it to your server together with the form.
  3. Your server calls POST /v1/siteverify with your secret key and the token.
  4. The service answers with HTTP 200 and success, score and the rest. Your server applies its threshold.

The token lives 300 seconds and verifies once. A second check answers timeout-or-duplicate.

  1. Create a site in the dashboard and keep the secret key (rgsk_...) on the server only.
  2. Install the server SDK for your language (Node, Python, PHP, Go, Java), or call the API directly.
  3. Verify with the hostname you expect, the action you expect and your minimum score.
  4. Accept the request only if the check says OK.
const outcome = await revokegpt.verify(token, {
expectedHostname: 'shop.example',
expectedAction: 'login',
minScore: 0.5,
remoteip: clientIp,
});
if (!outcome.ok) return reject(outcome.reason);

The secret goes in the body field secret or in Authorization: Bearer rgsk_..., never in both, never in the URL. Both application/x-www-form-urlencoded and application/json are accepted.

Terminal window
curl https://api.revokegpt.com/v1/siteverify \
-H 'Authorization: Bearer rgsk_...' \
-H 'Content-Type: application/json' \
-d '{"response":"<token>","remoteip":"203.0.113.7"}'
Request field Required Meaning
secret yes (unless Bearer) Your secret key.
response yes The token.
sitekey no The public key the token must belong to.
remoteip no The end user’s IPv4 or IPv6 address.

Our own endpoint rejects unknown fields (bad-request). The compatibility path /recaptcha/api/siteverify ignores them.

{
"success": true,
"score": 0.9,
"action": "login",
"hostname": "shop.example",
"challenge_ts": "2026-11-15T10:00:00Z",
"error-codes": []
}

/v1/siteverify also returns mode, reasons and cdata. Check action and hostname yourself if you do not use an SDK, and require success to be the boolean true.

Every input, authentication or authorization failure is an HTTP 200 with success: false and a list in error-codes. Only 413 (body too large) and 5xx are other statuses. Treat any non-200 as “not verified”.

Code What happened What to do
missing-input-secret No secret sent. Fix your server config.
invalid-input-secret Wrong or revoked secret. Check the key and the environment.
missing-input-response No token. The client did not send it; reject.
invalid-input-response The token is malformed or forged. Reject.
timeout-or-duplicate Expired (300 s) or already used. Ask the client for a new token.
sitekey-secret-mismatch The token belongs to another site. Use the matching key pair.
site-disabled Site switched off. Switch it on.
quota-exceeded Your plan’s checks are used up. See billing and spend cap.
plan-required, plan-restricted No active plan, or a restricted one. Fix billing.
bad-request Bad body, both secret forms, or an Origin header. Call from your server, not from a browser.
internal-error A fault on our side. Retry with a new token if your policy allows.

The full list is in error codes.

  • Call siteverify from your server only. A browser request (one with an Origin header) gets bad-request.
  • Fail closed: any network error, non-200 or unknown code means “do not accept”. After such an error the token may already be spent, so a retry needs a new token.
  • Pass remoteip from your trusted proxy, not the socket address behind a load balancer.
  • Check the hostname (or the app id for mobile tokens) and the action, so a token from another page cannot be replayed on yours.

Body limit applies (413 beyond it); the SDKs read at most 64 KiB of response. A token verifies once, for 300 seconds.