Skip to content

Operations

POST /v1/challenge

Request a challenge

The server determines the mode from the site configuration; the request has no mode field.

Authentication: none.

Request body (application/json):

Field Type Required Constraints Description
variant 1 object
sitekey string yes pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
hostname string yes minLength 1, maxLength 253, pattern ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$ Canonical hostname of the embedding page: equal to its own canonicalization (lowercase A-labels, no trailing dot, IPv4 in dotted-decimal form, valid punycode).
action string no pattern ^[A-Za-z0-9/_]{1,100}$
cdata string no pattern ^[A-Za-z0-9_-]{0,255}$
sdk object yes
sdk.name string yes minLength 1, maxLength 40, pattern ^[a-z0-9@/._-]{1,40}$ SDK name: a-z 0-9 @ / . _ -, 1 to 40 characters.
sdk.version string yes minLength 1, maxLength 40, pattern ^[0-9A-Za-z.+-]{1,40}$ SDK version: 0-9 A-Z a-z . + -, 1 to 40 characters.
variant 2 object
sitekey string yes pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
app object yes The app: its platform and its package name or bundle id.
action string no pattern ^[A-Za-z0-9/_]{1,100}$
cdata string no pattern ^[A-Za-z0-9_-]{0,255}$
sdk object yes
sdk.name string yes minLength 1, maxLength 40, pattern ^[a-z0-9@/._-]{1,40}$ SDK name: a-z 0-9 @ / . _ -, 1 to 40 characters.
sdk.version string yes minLength 1, maxLength 40, pattern ^[0-9A-Za-z.+-]{1,40}$ SDK version: 0-9 A-Z a-z . + -, 1 to 40 characters.

Responses:

Status Description
200 Challenge issued.
400 Malformed or invalid request.
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
413 Request body too large.
415 Unsupported media type (unsupported-media-type): a body whose media type is not application/json, or a non-identity Content-Encoding.
500 Internal error.

POST /v1/solve

Submit a challenge solution

A client that receives an unknown type MUST treat the solve as failed (not verified); it may retry or fall back.

Authentication: none.

Request body (application/json):

Field Type Required Constraints Description
challenge string yes minLength 1, maxLength 4096 Sealed, opaque challenge blob. Return it unchanged.
pow object yes
pow.solutions array of integer yes minItems 1, maxItems 256
signals string yes maxLength 49152 The browser signals, encrypted for this challenge with the key from the challenge response’s signals bootstrap; opaque to every client but the widget. The edge scores them (protocol v1 section 6): an empty string (the widget could not collect or encode them) is scored as missing signals, and text that does not decrypt and validate (another challenge’s key, an unsupported collector release, garbage) as invalid signals. Both are scored, never refused: the solve still gets a token, carrying its lower score.
attestation object no App solves only (M3): the attestation evidence for an app challenge, bound to it by the binding bytes of protocol v1 section 10. Absent on a web solve.

Responses:

Status Description
200 A response token, or a puzzle to solve.
400 Malformed or invalid request.
413 Request body too large.
415 Unsupported media type (unsupported-media-type): a body whose media type is not application/json, or a non-identity Content-Encoding.
500 Internal error.

POST /v1/puzzle/answer

Answer a puzzle

Checks the answer against the value sealed in the challenge. Each puzzle takes one answer (PUZZLE_MAX_ATTEMPTS) and its challenge string is then spent; the next response carries a fresh one. A person passes a group by answering PUZZLE_GROUP_CORRECT puzzles correctly (PUZZLE_GROUP_CORRECT_AUDIO in an audio group). A correct answer before that, or a wrong one within PUZZLE_GROUP_MAX_WRONG, returns the next puzzle of the group (step and steps count the progress); the answer that completes the group returns a token, and the wrong answer after PUZZLE_GROUP_MAX_WRONG wrong ones returns retry with a fresh challenge at PoW difficulty PUZZLE_POW_BUMP bits higher. A client that receives an unknown type MUST treat the answer as failed.

Authentication: none.

Request body (application/json):

Field Type Required Constraints Description
challenge string yes minLength 1, maxLength 4096 Sealed, opaque challenge blob. Return it unchanged.
answer integer yes minimum 0, maximum 359 The solver’s answer: slider position 0 to 100, rotation in degrees 0 to 359, or the index of the chosen option.
telemetry string yes maxLength 8192 Base64url of the interaction signals blob, sealed to the server with the same envelope as solve signals. A scoring input only; an empty string is scored as missing telemetry.

Responses:

Status Description
200 A token, the next puzzle of the group, or a fresh challenge.
400 Malformed or invalid request.
413 Request body too large.
415 Unsupported media type (unsupported-media-type): a body whose media type is not application/json, or a non-identity Content-Encoding.
500 Internal error.

POST /v1/siteverify

Verify a response token

Verifies a response token. Server-to-server only. Every input, authentication or authorization failure (missing or invalid secret; missing, invalid, expired or duplicate response; sitekey mismatch; disabled site; quota; a browser request carrying an Origin header) is answered with HTTP 200 and { "success": false, "error-codes": [...] }. A request carrying an Origin header gets error-codes: ["bad-request"] and no CORS headers. The only non-200 responses are 413 (body too large) and 5xx (internal error); clients MUST treat any non-200 as not verified. The secret is sent in the request body, or as Authorization: Bearer, never in the URL. A body in another media type, or with a non-identity Content-Encoding, is a malformed body: 200 with bad-request, never 415. Accepts application/x-www-form-urlencoded and application/json. (Server behaviour arrives in M1.) Firewall integrations send the secret as Authorization: Bearer rgsk_... instead of the body field secret; the secret is in exactly one of the two (both is bad-request). Unknown request fields are rejected (bad-request).

Authentication: none or secretKey.

Request body (application/x-www-form-urlencoded):

Field Type Required Constraints Description
secret string yes minLength 1, maxLength 128
response string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$ The response token: 1 to 2048 characters of unpadded base64url (A-Z a-z 0-9 - _).
sitekey string no pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
remoteip one of no End-user IP address: IPv4 (dotted decimal) or IPv6, including IPv4-mapped forms such as ::ffff:192.0.2.1.

Request body (application/json):

Field Type Required Constraints Description
secret string yes minLength 1, maxLength 128
response string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$ The response token: 1 to 2048 characters of unpadded base64url (A-Z a-z 0-9 - _).
sitekey string no pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
remoteip one of no End-user IP address: IPv4 (dotted decimal) or IPv6, including IPv4-mapped forms such as ::ffff:192.0.2.1.

Responses:

Status Description
200 Verification result. success: false with error-codes for every input, authentication or authorization failure.
413 Request body too large.
500 Internal error.

POST /v1/assessments

Create an assessment (token or express)

Server-to-server. A token assessment verifies a response token (one use, shared with siteverify) and returns its score and reasons; an express assessment (event.express: true) scores event.userIpAddress with no token. Body limit 8 KiB. JSON only; a query string or an Origin header is bad-request. event.userInfo is accepted as before and ignored when the site has neither account protection nor MFA on, and under ACCOUNT_KILL. Account verification (accountVerification) and the pair leak check (privatePasswordLeakVerification) are each off until the site enables them (403 feature-disabled). Payment fraud (event.transactionData, section 20) and SMS toll fraud (a phone number in event.userInfo, section 21) are each off until the site enables them (403 feature-disabled); event.fraudPrevention: DISABLED skips payment scoring. A card number, expiry, CVV or track data in transactionData is bad-request. Every other field not listed is rejected. The shadow score, the model, the fired rules and the rule, count or threshold behind a label are never returned.

Authentication: secretKey.

Request body (application/json):

Field Type Required Constraints Description
event object yes
event.token string no minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$
event.siteKey string no pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
event.expectedAction string no pattern ^[A-Za-z0-9/_]{1,100}$
event.express boolean no
event.userIpAddress string no maxLength 45 End-user IP address (IPv4 or IPv6). Express only.
event.userAgent string no maxLength 1000
event.headers array of string no maxItems 50
event.ja4 string no maxLength 64
event.requestedUri string no maxLength 2048
event.userInfo object no
event.userInfo.accountId string no minLength 1, maxLength 256 Your account identifier: 1 to 256 UTF-8 bytes. Send this or hashedAccountId, never both.
event.userInfo.hashedAccountId string no pattern ^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$ A hash of your account identifier you computed: canonical padded standard base64 of exactly 32 bytes (44 characters). Send this or accountId, never both.
event.userInfo.createAccountTime string no pattern ^(?:(?:[0-9][0-9][2468][048]|[0-9][0-9][13579][26]|[0-9][0-9]0[48]|[02468][048]00|[13579][26]00)-02-29|[0-9]{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30)|(?:02)-(?:0[1-9]|1[0-9]|2[0-8])))T(?:(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|([+-](?:[01][0-9]|2[0-3]):[0-5][0-9])))$ When the account was created (RFC 3339). At most 600 seconds before now makes the assessment an account creation; otherwise it is a login.
event.userInfo.userIds array of object no maxItems 10 Accepted for compatibility. Ignored, except that with the site’s smsTollFraud flag on the first phoneNumber is scored for SMS toll fraud (section 21): it is used only in request memory, stored only as keyed hashes and never logged. Nothing else here is stored, hashed or logged.
event.userInfo.userIds[].email string no minLength 1, maxLength 320
event.userInfo.userIds[].phoneNumber string no minLength 1, maxLength 32
event.userInfo.userIds[].username string no minLength 1, maxLength 256
event.fraudPrevention “FRAUD_PREVENTION_UNSPECIFIED” \ “ENABLED” \ “DISABLED” no
event.transactionData object no
event.transactionData.transactionId string no maxLength 128
event.transactionData.paymentMethod string no pattern ^(credit-card|debit-card|gift-card|processor-[a-z0-9-]{1,32}|custom-[a-z0-9-]{1,32})$
event.transactionData.cardBin string no pattern ^([0-9]{6}|[0-9]{8})$
event.transactionData.cardLastFour string no pattern ^[0-9]{4}$
event.transactionData.currencyCode string no pattern ^[A-Z]{3}$
event.transactionData.value number no minimum 0, maximum 1000000000000
event.transactionData.shippingValue number no minimum 0, maximum 1000000000000
event.transactionData.shippingAddress object no
event.transactionData.shippingAddress.recipient string no maxLength 100
event.transactionData.shippingAddress.address array of string no maxItems 4
event.transactionData.shippingAddress.locality string no maxLength 100
event.transactionData.shippingAddress.administrativeArea string no maxLength 100
event.transactionData.shippingAddress.regionCode string no pattern ^[A-Z]{2}$
event.transactionData.shippingAddress.postalCode string no maxLength 16
event.transactionData.billingAddress object no
event.transactionData.billingAddress.recipient string no maxLength 100
event.transactionData.billingAddress.address array of string no maxItems 4
event.transactionData.billingAddress.locality string no maxLength 100
event.transactionData.billingAddress.administrativeArea string no maxLength 100
event.transactionData.billingAddress.regionCode string no pattern ^[A-Z]{2}$
event.transactionData.billingAddress.postalCode string no maxLength 16
event.transactionData.user object no
event.transactionData.user.accountId string no maxLength 256
event.transactionData.user.creationMs string no pattern ^[0-9]{1,13}$
event.transactionData.user.email string no maxLength 320
event.transactionData.user.emailVerified boolean no
event.transactionData.user.phoneNumber string no maxLength 32
event.transactionData.user.phoneVerified boolean no
event.transactionData.merchants array of object no maxItems 5
event.transactionData.merchants[].accountId string no maxLength 256
event.transactionData.merchants[].creationMs string no pattern ^[0-9]{1,13}$
event.transactionData.merchants[].email string no maxLength 320
event.transactionData.merchants[].emailVerified boolean no
event.transactionData.merchants[].phoneNumber string no maxLength 32
event.transactionData.merchants[].phoneVerified boolean no
event.transactionData.items array of object no maxItems 20
event.transactionData.items[].name string no maxLength 100
event.transactionData.items[].value number no minimum 0, maximum 1000000000000
event.transactionData.items[].quantity integer no minimum 0, maximum 1000000
event.transactionData.items[].merchantAccountId string no maxLength 128
event.transactionData.gatewayInfo object no
event.transactionData.gatewayInfo.name string no pattern ^[a-z0-9_-]{1,32}$
event.transactionData.gatewayInfo.gatewayResponseCode string no maxLength 64
event.transactionData.gatewayInfo.avsResponseCode string no maxLength 8
event.transactionData.gatewayInfo.cvvResponseCode string no maxLength 8
accountVerification object no
accountVerification.endpoints array of one of yes minItems 1, maxItems 2
accountVerification.languageCode string no maxLength 35, pattern ^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8}){0,3}$
privatePasswordLeakVerification object no
privatePasswordLeakVerification.lookupHashPrefix string yes pattern ^[0-9a-f]{6}[048c]$ The bucket of the username: the first 26 bits of SHA-256 of the canonical username, 7 lowercase hex characters (bucketOf).
privatePasswordLeakVerification.encryptedUserCredentialsHash string yes pattern ^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$ The blinded OPRF element of the canonical username and password: 32 bytes, unpadded base64url (43 characters).

Responses:

Status Description
200 The assessment.
400 Malformed or invalid request (bad-request).
401 Missing, invalid or management secret, or a disabled site (unauthorized): one uniform answer.
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
403 The site has not enabled this endpoint (feature-disabled).
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.
503 Assessments are switched off or unavailable (service-unavailable). Siteverify is unaffected.

POST /v1/assessments/{id}:annotate

Annotate an assessment

Labels an assessment of the authenticated site. A wrong site, a forged or altered id and a bad version are one 404 not-found; an id older than 30 days is 410 expired. Body limit 2 KiB. PASSWORD_* annotations are bad-request. transactionEvent reports the outcome of a scored payment; the reason PAYMENT_FRAUD is an alias the edge rewrites (section 20).

Authentication: secretKey.

Parameters:

Name In Required Type
id path yes string

Request body (application/json):

Field Type Required Constraints Description
annotation “LEGITIMATE” \ “FRAUDULENT” no
reasons array of “CHARGEBACK” \ “CHARGEBACK_FRAUD” \ “CHARGEBACK_DISPUTE” \ “REFUND” \
accountId string no minLength 1, maxLength 256 Your account identifier: 1 to 256 UTF-8 bytes. Send this or hashedAccountId, never both.
hashedAccountId string no pattern ^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$ A hash of your account identifier you computed: canonical padded standard base64 of exactly 32 bytes (44 characters). Send this or accountId, never both.
transactionEvent object no
transactionEvent.eventType “TRANSACTION_EVENT_TYPE_UNSPECIFIED” \ “MERCHANT_APPROVE” \ “MERCHANT_DENY” \ “MANUAL_REVIEW” \
transactionEvent.reason string no maxLength 64
transactionEvent.value number no minimum 0, maximum 1000000000000
transactionEvent.eventTime string no pattern ^(?:(?:[0-9][0-9][2468][048]|[0-9][0-9][13579][26]|[0-9][0-9]0[48]|[02468][048]00|[13579][26]00)-02-29|[0-9]{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30)|(?:02)-(?:0[1-9]|1[0-9]|2[0-8])))T(?:(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|([+-](?:[01][0-9]|2[0-3]):[0-5][0-9])))$

Responses:

Status Description
200 Recorded. Empty object.
400 Malformed or invalid request (bad-request).
401 Missing, invalid or management secret, or a disabled site (unauthorized): one uniform answer.
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
403 The site has not enabled this endpoint (feature-disabled).
404 Unknown assessment (not-found).
410 Assessment older than 30 days (expired).
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.
503 Assessments are switched off or unavailable (service-unavailable). Siteverify is unaffected.

POST /v1/password-check

Check a password against the leaked-password ranges

Server-to-server. The body is the first 5 hex characters of the SHA-1 of the password; the answer is every leaked suffix with that prefix as SUFFIX35:COUNT lines (35 uppercase hex characters, a colon, a decimal count), CRLF separated, padded with fake count-0 lines to 800 to 1000 lines when shorter. The caller compares the suffix locally and ignores count 0. Cache-Control: private, no-store. Body limit 1 KiB. A prefix of any other length, a full hash or a non-hex character is bad-request. A missing range answers 503 service-unavailable, never an empty list.

Authentication: secretKey.

Request body (application/json):

Field Type Required Constraints Description
prefix string yes pattern ^[0-9A-Fa-f]{5}$ The first 5 hexadecimal characters of the SHA-1 of the password (either case).

Responses:

Status Description
200 The range, as text/plain lines SUFFIX35:COUNT.
400 Malformed or invalid request (bad-request).
401 Missing, invalid or management secret, or a disabled site (unauthorized): one uniform answer.
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
403 The site has not enabled this endpoint (feature-disabled).
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.
503 Assessments are switched off or unavailable (service-unavailable). Siteverify is unaffected.

POST /v1/accounts:erase

Erase the stored profile of an account

Server-to-server. Deletes the profile and the related-account entries kept for the account of the authenticated site (GDPR erasure). Answers 200 whether or not anything was stored. Needs a valid site secret only: no feature flag, and neither ACCOUNT_KILL nor ASSESS_KILL stops it. Body limit 1 KiB. Exactly one of accountId and hashedAccountId.

Authentication: secretKey.

Request body (application/json):

Field Type Required Constraints Description
accountId string no minLength 1, maxLength 256 Your account identifier: 1 to 256 UTF-8 bytes. Send this or hashedAccountId, never both.
hashedAccountId string no pattern ^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$ A hash of your account identifier you computed: canonical padded standard base64 of exactly 32 bytes (44 characters). Send this or accountId, never both.

Responses:

Status Description
200 Done. Empty object.
400 Malformed or invalid request (bad-request).
401 Missing, invalid or management secret, or a disabled site (unauthorized): one uniform answer.
403 The site has not enabled this endpoint (feature-disabled).
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.
503 Assessments are switched off or unavailable (service-unavailable). Siteverify is unaffected.

POST /v1/mfa/send

Send the one-time code

Widget-facing, with the CORS and Origin rules of /v1/solve. Authenticated by the requestToken of an assessment response only. Body limit 1 KiB. Sends a six-digit code to the endpoint of the session: at most 3 sends per session, 60 seconds apart. A send that cannot happen answers 200 with a result instead of sent.

Authentication: none.

Request body (application/json):

Field Type Required Constraints Description
requestToken string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$

Responses:

Status Description
200 Sent, or a final result.
400 Malformed or invalid request (bad-request).
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
403 The site has not enabled account verification (feature-disabled).
404 Forged, malformed or expired requestToken, or an unknown or disabled site (not-found): one answer in body and status.
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.
503 Account verification is switched off or unavailable (service-unavailable). Siteverify is unaffected.

POST /v1/mfa/verify

Verify the one-time code

Widget-facing, with the CORS and Origin rules of /v1/solve. Authenticated by the requestToken only. Body limit 1 KiB. A session allows 5 wrong codes in total. A wrong code with attempts left answers retry; the right code, and the last wrong one, answer a final token (whose assessment says SUCCESS_USER_VERIFIED or ERROR_USER_NOT_VERIFIED), given once per session. A session that is unknown or already over also answers retry.

Authentication: none.

Request body (application/json):

Field Type Required Constraints Description
requestToken string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$
code string yes pattern ^[0-9]{6}$

Responses:

Status Description
200 A final token, or retry.
400 Malformed or invalid request (bad-request).
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
403 The site has not enabled account verification (feature-disabled).
404 Forged, malformed or expired requestToken, or an unknown or disabled site (not-found): one answer in body and status.
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.
503 Account verification is switched off or unavailable (service-unavailable). Siteverify is unaffected.

GET /v1/policies/{siteKey}

Fetch the signed firewall policy bundle of a site

Public by site key, unless the owner marked the bundle private: then Authorization: Bearer rgsk_... (the site secret) is required and a missing or wrong one is 401 unauthorized. Returns the bundle of section 18.5 as JSON with an ETag; a request with a matching If-None-Match gets 304. Cached for 60 seconds at the edge. The bundle is signed (Ed25519): integrations verify it against pinned keys and never trust the transport. An unknown or disabled site, and a site that has published no policy, are one 404 not-found. Integrations that hold a secret send it on every fetch (section 18.5).

Authentication: none or secretKey.

Parameters:

Name In Required Type
siteKey path yes string

Responses:

Status Description
200 The signed bundle.
304 Not modified.
401 A private bundle fetched without the matching site secret as Bearer (unauthorized).
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
404 Unknown site or no published policy (not-found).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.

GET /.well-known/rg-keys.json

Public signing keys

The public halves of the bundle and session signing keys, with kid and notAfter, for monitoring and rotation. Integrations pin their keys (PINNED_POLICY_KEYS); this file never replaces the pins. (Server behaviour arrives in M9 Task 5.)

Authentication: none.

Responses:

Status Description
200 The keys.
500 Internal error.

POST /v1/session

Exchange a response token for a session or clearance token

Widget-facing, with the CORS and Origin rules of /v1/solve (the widget frame calls it). Spends the response token (one use) and returns an offline-verifiable token (section 18.6) that the page hands to the integration once, in the X-RG-Session-Init header (session) or the rg_clearance field of the /__rg/return form (clearance). The optional X-RG-Session-Prev header carries the previous session so its hard maximum age is kept. Body limit 1 KiB. 20 requests per second per site.

Authentication: none.

Request body (application/json):

Field Type Required Constraints Description
sitekey string yes pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
token string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$ A response token from /v1/solve: action rg_session for kind session, rg_challenge for kind clearance. It is spent here (one use).
kind “session” \ “clearance” yes

Responses:

Status Description
200 The token.
400 Malformed request, unknown or disabled site (bad-request, invalid-site-key, site-disabled), a hostname the site does not allow (hostname-not-allowed), or a response token that is invalid (MALFORMED), expired (EXPIRED), already spent (DUPE) or of the wrong action (UNEXPECTED_ACTION).
402 The organization has no active plan (plan-required), or its plan is restricted for this endpoint (plan-restricted). Section 19.
403 A refresh past the first token’s hard maximum age (session-expired).
413 Request body too large.
415 Unsupported media type (unsupported-media-type).
429 Rate limited (rate-limited). Carries Retry-After: 1.
500 Internal error.

POST /recaptcha/api/siteverify

Verify a response token (drop-in compatible path)

Verifies a response token. Server-to-server only. Every input, authentication or authorization failure (missing or invalid secret; missing, invalid, expired or duplicate response; sitekey mismatch; disabled site; quota; a browser request carrying an Origin header) is answered with HTTP 200 and { "success": false, "error-codes": [...] }. A request carrying an Origin header gets error-codes: ["bad-request"] and no CORS headers. The only non-200 responses are 413 (body too large) and 5xx (internal error); clients MUST treat any non-200 as not verified. The secret is sent in the request body, or as Authorization: Bearer, never in the URL. A body in another media type, or with a non-identity Content-Encoding, is a malformed body: 200 with bad-request, never 415. Accepts application/x-www-form-urlencoded and application/json. (Server behaviour arrives in M1.) Firewall integrations send the secret as Authorization: Bearer rgsk_... instead of the body field secret; the secret is in exactly one of the two (both is bad-request). Unknown request fields (for example version from existing server libraries) are ignored.

Authentication: none or secretKey.

Request body (application/x-www-form-urlencoded):

Field Type Required Constraints Description
secret string yes minLength 1, maxLength 128
response string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$ The response token: 1 to 2048 characters of unpadded base64url (A-Z a-z 0-9 - _).
sitekey string no pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
remoteip string no End-user IP address (IPv4 or IPv6). An invalid value is ignored, not rejected.

Request body (application/json):

Field Type Required Constraints Description
secret string yes minLength 1, maxLength 128
response string yes minLength 1, maxLength 2048, pattern ^[A-Za-z0-9_-]{1,2048}$ The response token: 1 to 2048 characters of unpadded base64url (A-Z a-z 0-9 - _).
sitekey string no pattern ^rgpk_[0-9A-Za-z]{20}$ Public site key.
remoteip string no End-user IP address (IPv4 or IPv6). An invalid value is ignored, not rejected.

Responses:

Status Description
200 Verification result. success: false with error-codes for every input, authentication or authorization failure.
413 Request body too large.
500 Internal error.