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.
When to use it
Section titled “When to use it”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).
How it works
Section titled “How it works”- The client obtains a response token (1 to 2048 characters of
A-Z a-z 0-9 - _). - The client sends it to your server together with the form.
- Your server calls
POST /v1/siteverifywith your secret key and the token. - The service answers with HTTP 200 and
success,scoreand the rest. Your server applies its threshold.
The token lives 300 seconds and verifies once. A second check answers timeout-or-duplicate.
Step by step
Section titled “Step by step”- Create a site in the dashboard and keep the secret key (
rgsk_...) on the server only. - Install the server SDK for your language (Node, Python, PHP, Go, Java), or call the API directly.
- Verify with the hostname you expect, the action you expect and your minimum score.
- Accept the request only if the check says OK.
With an SDK
Section titled “With an SDK”const outcome = await revokegpt.verify(token, { expectedHostname: 'shop.example', expectedAction: 'login', minScore: 0.5, remoteip: clientIp,});if (!outcome.ok) return reject(outcome.reason);With plain HTTP
Section titled “With plain HTTP”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.
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.
The answer
Section titled “The answer”{ "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.
Error codes
Section titled “Error codes”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.
Security notes
Section titled “Security notes”- Call siteverify from your server only. A browser request (one with an
Originheader) getsbad-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
remoteipfrom 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.
Limits
Section titled “Limits”Body limit applies (413 beyond it); the SDKs read at most 64 KiB of response. A token verifies once, for 300 seconds.