Fraud Prevention Data API
The Data API is the server-side counterpart to the Web SDK. Use it to pull verdicts, aggregate statistics, and export data for reporting and reconciliation — pulling the numbers your own systems agree on.
Base URL
https://verify.captcha.laAuthentication
All Data API requests are authenticated with your Fraud Prevention application credentials, sent as headers:
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRETWARNING
X-App-Secret is server-side only. Never expose it to browsers, mobile apps, or public repositories. The page SDK only ever uses the public appKey.
Endpoints
Fetch a verdict
Retrieve the verdict for a single visit (e.g. to reconcile a specific visit). Pass exactly one identifier: verdict_id (from the verdict the page received) or cid (the click id, for click-token traffic).
GET /v1/bot/verdict?verdict_id=VERDICT_ID
GET /v1/bot/verdict?cid=CID_OF_THE_VISIT
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRETfound tells you whether a verdict was found. When it is true, data holds the verdict fields described in the Verdict Reference:
{
"found": true,
"data": {
"cid": null,
"verdict_id": "vd_3f9c0a7e5b1d4c2a9e8f7b6a",
"is_bot": true,
"score": 87,
"level": "high",
"action": "flag",
"reasons": ["automation", "network"],
"consistency": { "ok": false },
"degraded": false,
"created_at": "2026-06-25 00:00:00"
}
}When nothing matches, the response is {"found": false}. A request with neither verdict_id nor cid is rejected with HTTP 400.
TIP
Verdicts are stored a few seconds after they are produced, so a lookup made right after the visit can return found: false. To check a visit in real time, use Verify a verdict token instead.
Verify a verdict token
Check a verdict_token that your page received from the Web SDK. Use this to gate content on your server (see Server-side verification). The check is answered immediately and does not depend on stored data.
POST /v1/bot/verdict/verify
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET
Content-Type: application/json
{ "token": "vt1.eyJ2Ijoi...", "ip": "203.0.113.7", "consume": false }| Parameter | Required | Description |
|---|---|---|
token | yes | The verdict_token from the verdict. |
ip | no | The visitor's IP address as your server sees it. When given, the token must come from the same network as the visit. Recommended. |
consume | no | true = the token can be used only once; a second check returns already_used. Default false: the token can be checked again until it expires. |
{
"valid": true,
"error": null,
"verdict_id": "vd_3f9c0a7e5b1d4c2a9e8f7b6a",
"expired": false,
"expires_at": 1767225600,
"ip_match": true,
"verdict": {
"is_bot": false,
"level": "low",
"action": "record_only",
"score": 12,
"degraded": false,
"reasons": [],
"issued_at": 1767225000
}
}| Field | Description |
|---|---|
valid | true when the token is authentic, belongs to your app, has not expired, matches ip (if given) and, with consume, has not been used. valid only says the token is genuine. It does not say the visitor is human, so also check verdict. |
error | null, or why the token is not valid: malformed, bad_signature, expired, ip_mismatch, already_used, unavailable (the one-time check could not be completed; retry). |
expired / expires_at | Expiry state and expiry time (Unix seconds). |
ip_match | true / false when ip was given, otherwise null. |
verdict | The signed verdict: is_bot, level, action, score, degraded, reasons, issued_at. null when the token could not be read. |
A typical gate serves the content when valid is true and verdict.is_bot is false. Decide yourself how to treat verdict.degraded and requests that have no token at all. If you fail open, real visitors still get through during an outage. If you fail closed, nothing gets through without a valid token.
Tokens expire after 10 minutes by default. Re-run the SDK (for example on the next page load) to get a fresh one.
Aggregated stats
Pull counts over a time range (totals, bots, and the breakdown by level and by day) for dashboards and quality reports.
GET /v1/bot/stats?from=2026-06-01&to=2026-06-30
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET{
"from": "2026-06-01",
"to": "2026-06-30",
"cleaned": true,
"total": 124500,
"bots": 18230,
"by_level": { "low": 100300, "medium": 16900, "high": 6200, "critical": 1100 },
"by_day": [
{ "date": "2026-06-01", "total": 4100, "bots": 590 }
]
}from / to default to the last 7 days.
Export
Export per-visit verdict rows for a time range, for offline reconciliation. Rows are returned newest first, in pages.
GET /v1/bot/export?from=2026-06-01&to=2026-06-30&limit=1000
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET| Parameter | Description |
|---|---|
from / to | Date range (YYYY-MM-DD). Optional. |
limit | Rows per page, 1–5000 (default 1000). |
cursor | Pass the previous page's next_cursor to get the next page. |
{
"rows": [
{
"id": 1042, "cid": null, "verdict_id": "vd_3f9c0a7e5b1d4c2a9e8f7b6a",
"is_bot": false, "score": 12, "level": "low", "action": "record_only",
"reasons": [], "consistency": { "ok": true }, "degraded": false,
"created_at": "2026-06-25 00:00:00", "rescored": false
}
],
"next_cursor": 1042
}Each row carries the visit's identifiers, timestamp, and verdict fields, so you can join it back to your own logs. next_cursor is null on the last page.
Cleaned figures
Stats and exports are reported on a cleaned basis by default: traffic that is later identified as invalid is continuously re-evaluated and removed from the numbers. This happens asynchronously, so figures for very recent windows may still settle slightly. Pass ?raw=1 to see the un-cleaned figures; in export, each row also carries a rescored flag.
Per-click reconciliation
For paid-traffic scenarios, a single visit can be tied back to a specific delivered click so two parties can settle on it. That uses a click token and is covered in the Ad fraud guide.
Click token reference (for traffic providers)
A traffic provider signs a click token on its own server and adds it to the destination URL, so the verdict for the resulting visit is attributed back to the provider. Signing is offline — no API call.
Get your signing credentials
In the dashboard, open your app → Fraud Prevention → Issue signing key. You receive:
bot_kid— your public key id (goes into the token aspkid).bot_hmac_secret— your signing secret, shown once. Keep it server-side.
Token format
ct.<base64url(payload)>.<base64url(HMAC_SHA256(body, bot_hmac_secret))>body is the base64url of the JSON payload; the signature is computed over that body string.
Payload fields
| field | required | description |
|---|---|---|
pkid | yes | your bot_kid; the backend uses it to look up your secret and verify the signature |
cid | yes | unique id for this click; the reconciliation key. Generate a fresh, unique value per click |
aud | no | the target advertiser's app_key. When set, the token is only honored on that advertiser's page. Omit to let any advertiser page accept it |
click_ts | no | unix seconds when the click happened |
exp | no | unix seconds expiry; expired tokens are rejected |
Add it to the link
Append the token as the _ctk query parameter on the advertiser's destination URL:
https://advertiser.example/lp?_ctk=ct.<...>.<...>The advertiser's SDK reads _ctk automatically (configurable via tokenParam). Each cid is replay-protected: the same visitor reloading the page is fine, but a token reused somewhere else is flagged. See the Security model.
Example (pseudo-code)
const payload = { pkid, cid, aud: advertiserAppKey, click_ts: now, exp: now + 900 }
const body = base64url(JSON.stringify(payload))
const sig = base64url(hmacSha256(body, botHmacSecret))
const token = `ct.${body}.${sig}`
const url = `${destination}?_ctk=${encodeURIComponent(token)}`Postback (server-to-server)
Instead of polling the Data API, you can have verdicts pushed to your own endpoint as they happen — handy for affiliate trackers and advertiser back-ends that want to record or reconcile each visit in real time.
Enable it
In the dashboard, open your app → Fraud Prevention → set Postback URL (bot_postback_url). Once set, every verdict is POSTed to that URL shortly after it is produced. Delivery is asynchronous and isolated — a slow or failing endpoint never affects the verdict already returned to the page SDK.
When it fires
On each verify that produces a verdict for the app. Delivery is best-effort with a few automatic retries; treat it as at-least-once and dedupe on verdict_id.
Request
POST <your bot_postback_url>
Content-Type: application/json
X-Bot-Signature: t=<unix_ts>,v=<hex>Body (JSON):
{
"cid": "CID_OF_THE_VISIT",
"verdict_id": "vd_3f9c0a7e5b1d4c2a9e8f7b6a",
"is_bot": 1,
"score": 87,
"level": "high",
"action": "flag",
"advertiser_app_id": 12,
"provider_app_id": 34,
"created_at": "2026-06-25 00:00:00"
}| field | description |
|---|---|
cid | reconciliation key for the visit (may be null if no click token was present) |
verdict_id | id of the verdict; same value the page received |
is_bot | 1 / 0 |
score | risk score |
level | low / medium / high / critical |
action | server-authoritative action (record_only / flag / challenge / deny) |
advertiser_app_id | id of the app the verify ran for |
provider_app_id | traffic provider id when attributed via a click token, else null |
created_at | verdict time (UTC) |
Verify the signature
The X-Bot-Signature header lets you confirm the request really came from us. It is t=<unix_ts>,v=<hex> where:
hex = HMAC_SHA256( "<unix_ts>." + raw_request_body , bot_hmac_secret )bot_hmac_secret is the same signing secret you issue under Fraud Prevention → Issue signing key. To verify, recompute the HMAC over the raw body you received (do not re-serialize the JSON) and compare in constant time. Optionally reject requests whose t is too far from your clock to bound replay.
// Express example
const [tsPart, vPart] = req.get('X-Bot-Signature').split(',')
const ts = tsPart.slice(2) // "t=" prefix
const v = vPart.slice(2) // "v=" prefix
const expected = crypto
.createHmac('sha256', BOT_HMAC_SECRET)
.update(ts + '.' + rawBody) // rawBody is the unparsed request body
.digest('hex')
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v))Next steps
- Verdict Reference — the fields returned by these endpoints
- Web SDK — collect verdicts on your page