Docs menu
Guides
API reference
POST /api/v1/siteverify
Redeem a check token. The browser script and the backend token check. Generated from the OpenAPI file.
Last updated
Overview
POST https://api.inlineshield.io/api/v1/siteverify
Your backend sends the token that inlineshield.js put in the form, with the email the player submitted, and gets the decision recorded by /check. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.
Token problems are answered with HTTP 200 and success: false. QUOTA_EXCEEDED means the token is missing because the account is over its quota (/check issued none). Nothing here counts against the quota.
Limited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created).
Authentication
Send your secret API key in the X-Api-Key header.
Your secret API key (bs_live_… or bs_test_…), from the console under Settings › Keys. Never put it in a browser or an app. The header name X-ApiKey is also accepted (deprecated).
Request body
JSON (Content-Type: application/json), required.
| Field | Type | Required | Description |
|---|---|---|---|
token | string | no | The token from /check (inlineshield.js puts it in the form). |
email | string | yes | The email the player submitted. Must be the one that was checked.at least 1 character |
Request examples
{
"token": "bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i",
"email": "allow@test.inlineshield.io"
}{
"token": "bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i",
"email": "kyc@test.inlineshield.io"
}{
"email": "allow@test.inlineshield.io"
}{
"token": "not-a-real-token",
"email": "allow@test.inlineshield.io"
}The first example as a cURL command:
curl -X POST https://api.inlineshield.io/api/v1/siteverify \
-H "X-Api-Key: $INLINESHIELD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"token": "bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i",
"email": "allow@test.inlineshield.io"
}'Responses
200 OK
success: true with the decision (a live hold also has reviewId), or success: false with the reason.
Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
One of 2 shapes:
SiteverifySuccess
| Field | Type | Required | Description |
|---|---|---|---|
success | true | yes | |
decision | string | yes | ALLOWED: let the player in. QUARANTINED: hold for review. BLOCKED: refuse.Values: ALLOWED, QUARANTINED, BLOCKED |
riskScore | number | yes | 0 (lowest risk) to 100.0 to 100 |
reasons | array of string | yes | Plain-language reasons for the result. |
requestId | string | yes | The screening's id. Use it for feedback and support.matches ^AUD- |
action | string | yes | What to do with the sign-up: ALLOWED → allow, QUARANTINED → hold, BLOCKED → block.Values: allow, hold, block |
recommendedAction | string | yes | Advice next to action: allow, allow without a sign-up bonus, review, block, or ask for KYC before paying out.Values: allow, allow_no_bonus, review, block, require_kyc |
reviewId | string | no | Live holds only.matches ^rev_ |
SiteverifyFailure
| Field | Type | Required | Description |
|---|---|---|---|
success | false | yes | |
error | string | yes | NO_TOKEN: no token was sent. INVALID_TOKEN: not a token of this account. EXPIRED_TOKEN: older than 10 minutes. TOKEN_ALREADY_USED: redeemed before. EMAIL_MISMATCH: issued for another email. QUOTA_EXCEEDED: no token was sent and the account is over its quota.Values: NO_TOKEN, INVALID_TOKEN, EXPIRED_TOKEN, TOKEN_ALREADY_USED, EMAIL_MISMATCH, QUOTA_EXCEEDED |
{
"success": true,
"decision": "ALLOWED",
"riskScore": 0,
"reasons": [
"Test mode: allow@test.inlineshield.io always gives ALLOWED / allow."
],
"requestId": "AUD-MHH3K2QZ-4F1C9B2E7D10",
"action": "allow",
"recommendedAction": "allow"
}{
"success": true,
"decision": "QUARANTINED",
"riskScore": 60,
"reasons": [
"Test mode: kyc@test.inlineshield.io always gives QUARANTINED / require_kyc."
],
"requestId": "AUD-MHH3K32F-7E2A4C6B8D90",
"action": "hold",
"recommendedAction": "require_kyc"
}{
"success": false,
"error": "NO_TOKEN"
}{
"success": false,
"error": "INVALID_TOKEN"
}400 Bad Request
No email, or (without the rate-limit headers) a body that is not valid JSON.
Headers: X-RateLimit-Limit (optional), X-RateLimit-Remaining (optional), X-RateLimit-Reset (optional).
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Values: BAD_REQUEST |
message | string | yes |
401 Unauthorized
No X-Api-Key header, or an unknown, revoked or expired key.
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Values: UNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEY, ORGANIZATION_NOT_FOUND |
message | string | yes |
{
"error": "UNAUTHORIZED",
"message": "Access denied: Missing required X-Api-Key header."
}{
"error": "INVALID_API_KEY",
"message": "Invalid API key provided."
}403 Forbidden
The account is suspended.
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Values: TENANT_SUSPENDED |
message | string | yes |
429 Too Many Requests
The per-minute limit of this key.
Headers: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Values: RATE_LIMIT_EXCEEDED |
message | string | yes |
{
"error": "RATE_LIMIT_EXCEEDED",
"message": "Siteverify rate limit of 1200 req/min exceeded. Try again in 12 seconds."
}500 Internal Server Error
Internal error.
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Values: VERIFICATION_ERROR, AUTH_ERROR |
message | string | yes |
503 Service Unavailable
The key could not be checked right now. Try again.
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Values: DATABASE_ERROR |
message | string | yes |
Errors
Errors are JSON, { "error": "CODE", "message": "…" }. Branch on error, never on message.
| HTTP status | error | When |
|---|---|---|
400 | BAD_REQUEST | No email, or (without the rate-limit headers) a body that is not valid JSON. |
401 | UNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEY, ORGANIZATION_NOT_FOUND | No X-Api-Key header, or an unknown, revoked or expired key. |
403 | TENANT_SUSPENDED | The account is suspended. |
429 | RATE_LIMIT_EXCEEDED | The per-minute limit of this key. |
500 | VERIFICATION_ERROR, AUTH_ERROR | Internal error. |
503 | DATABASE_ERROR | The key could not be checked right now. Try again. |
See all errors for every endpoint.
Headers and limits
| Response header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current one-minute window. |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Seconds until the current window ends. |
Retry-After | Seconds to wait before trying again. |
The limits per endpoint and plan are on Rate limits and quotas.