Skip to content

反欺诈数据 API ​

数据 API 是 Web SDK 的服务端搭档。用它来拉取裁决、汇总统计、导出数据, 用于报表与对账——拉取你自己系统据以一致的那些数字。

基础 URL ​

https://verify.captcha.la

鉴权 ​

所有数据 API 请求都用你的反欺诈应用凭据鉴权,以请求头形式发送:

X-App-Key:    YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET

WARNING

X-App-Secret 仅限服务端。绝不要把它暴露给浏览器、移动端或公开仓库。 页面 SDK 始终只使用公开的 appKey。

端点 ​

获取单条裁决 ​

获取某一次访问的裁决(例如用于对账某次具体访问)。必须传一个标识:verdict_id(页面收到的裁决里带的)或 cid(点击 ID,用于带 click token 的流量)。

bash
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_SECRET

found 表示是否找到。为 true 时,data 是裁决字段参考里说明的各字段:

json
{
  "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"
  }
}

没有匹配时返回 {"found": false}。verdict_id 和 cid 都不传的请求返回 HTTP 400。

TIP

裁决在产生后几秒内才会入库,访问刚结束就查询可能返回 found: false。需要实时判断时请用校验裁决凭证。

校验裁决凭证 ​

校验页面从 Web SDK 拿到的 verdict_token,用于在服务端做内容墙(见服务端校验)。结果即时返回,不依赖入库数据。

bash
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 }
参数必填说明
token是裁决里的 verdict_token。
ip否你的服务端看到的访客 IP。传了之后,token 必须来自与本次访问相同的网络。建议传。
consume否true = token 只能用一次,第二次校验返回 already_used。默认 false:过期前可以反复校验。
json
{
  "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
  }
}
字段说明
validtoken 真实、属于你的应用、未过期、与 ip 匹配(若传了),并且在 consume 模式下未被用过时为 true。valid 只说明 token 是真的,不代表访客是真人,还要看 verdict。
errornull,或 token 无效的原因:malformed、bad_signature、expired、ip_mismatch、already_used、unavailable(一次性校验暂时无法完成,请重试)。
expired / expires_at是否过期,以及过期时间(Unix 秒)。
ip_match传了 ip 时为 true / false,否则为 null。
verdict签名里的裁决:is_bot、level、action、score、degraded、reasons、issued_at。token 无法解析时为 null。

常见做法:valid 为 true 且 verdict.is_bot 为 false 时返回内容。verdict.degraded 为 true,以及请求根本没带 token 时怎么处理,由你决定:选择放行,服务故障时真实访客仍能访问;选择拒绝,没有有效 token 就一律拒绝。

token 默认 10 分钟过期。需要新 token 时重新运行 SDK 即可(例如下一次页面加载)。

汇总统计 ​

按时间范围拉取计数(总量、机器人数,以及按 level 和按天的拆分),用于看板与质量报表。

bash
GET /v1/bot/stats?from=2026-06-01&to=2026-06-30
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET
json
{
  "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 默认最近 7 天。

导出 ​

按时间范围导出逐次访问的裁决行,用于离线对账。按时间倒序分页返回。

bash
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
参数说明
from / to日期范围(YYYY-MM-DD),可选。
limit每页行数,1–5000(默认 1000)。
cursor传上一页的 next_cursor 取下一页。
json
{
  "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
}

每一行携带该次访问的标识、时间戳和裁决字段,你可据此与自己的日志关联。最后一页的 next_cursor 为 null。

已清洗口径

统计与导出默认按已清洗口径返回:事后识别为无效的量会被持续重评估并从数字中 剔除。该过程异步进行,因此非常近期窗口的数字可能仍会小幅收敛。传 ?raw=1 可查看 未清洗的原始口径;在 export 中,每行还会携带 rescored 标记。

逐点击对账

对于付费流量场景,一次访问可以回溯到某次具体投递的点击,供双方就此结算。这用到 点击 token,见广告反作弊指南。

Click token 参考(给流量方) ​

流量方在自己的服务器上签一枚 click token,加到目标 URL 上,这样这次访问的裁决就能归属回该流量方。签名是离线的——不需要调用 API。

获取签名凭据 ​

在 dashboard 里打开你的 app → 反欺诈 → 签发签名密钥,会得到:

  • bot_kid —— 你的公开 key id(作为 token 里的 pkid)。
  • bot_hmac_secret —— 你的签名 secret,只显示一次,务必存在服务端。

Token 格式 ​

ct.<base64url(payload)>.<base64url(HMAC_SHA256(body, bot_hmac_secret))>

body 是 JSON payload 的 base64url;签名对该 body 字符串计算。

payload 字段 ​

字段必填说明
pkid是你的 bot_kid;后端据此反查你的 secret 验签
cid是本次点击的唯一 id,对账主键。每次点击生成全新唯一值
aud否目标广告主的 app_key。设了之后 token 只在该广告主页面被承接;不设则任意广告主页面都可承接
click_ts否点击发生的 unix 秒
exp否unix 秒过期时间;过期 token 被拒

加到链接上 ​

把 token 作为 _ctk 查询参数加到广告主目标 URL:

https://advertiser.example/lp?_ctk=ct.<...>.<...>

广告主的 SDK 会自动读取 _ctk(可用 tokenParam 配置参数名)。每个 cid 都有防重放保护:同一访客刷新页面不受影响,token 被拿到别处重复使用会被标记。见 安全模型。

示例(伪代码) ​

js
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(服务端到服务端推送) ​

除了轮询数据 API,你还可以让裁决在产生时主动推送到你自己的端点—— 对希望实时记录/对账每次访问的联盟 tracker 和广告主服务端很方便。

启用 ​

在 dashboard 里打开你的 app → 反欺诈 → 设置 Postback URL (bot_postback_url)。设了之后,每条裁决都会在产生后不久 POST 到该 URL。 推送是异步且隔离的——端点慢或失败,绝不影响已返回给页面 SDK 的裁决。

推送时机 ​

每次产生该 app 裁决的 verify 都会触发。推送尽力而为,带少量自动重试; 按 至少一次 语义处理,以 verdict_id 去重。

请求 ​

POST <你的 bot_postback_url>
Content-Type: application/json
X-Bot-Signature: t=<unix_ts>,v=<hex>

Body(JSON):

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"
}
字段说明
cid本次访问的对账主键(无 click token 时可能为 null)
verdict_id裁决 ID,与页面收到的一致
is_bot1 / 0
score风险分
levellow / medium / high / critical
action服务端权威 action(record_only / flag / challenge / deny)
advertiser_app_id本次 verify 所属 app 的 id
provider_app_id经 click token 归属时的流量方 id,否则为 null
created_at裁决时间(UTC)

验签 ​

X-Bot-Signature 头让你确认请求确实来自我们。格式为 t=<unix_ts>,v=<hex>,其中:

hex = HMAC_SHA256( "<unix_ts>." + 原始请求体 , bot_hmac_secret )

bot_hmac_secret 就是你在反欺诈 → 签发签名密钥 拿到的那枚签名 secret。 验签时对收到的原始 body 重算 HMAC(不要把 JSON 重新序列化),常量时间比较。 可选地拒绝 t 与本机时钟偏差过大的请求以限制重放。

js
// Express 示例
const [tsPart, vPart] = req.get('X-Bot-Signature').split(',')
const ts = tsPart.slice(2)             // 去掉 "t=" 前缀
const v  = vPart.slice(2)              // 去掉 "v=" 前缀
const expected = crypto
  .createHmac('sha256', BOT_HMAC_SECRET)
  .update(ts + '.' + rawBody)          // rawBody 是未解析的原始请求体
  .digest('hex')
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v))

下一步 ​

MIT-licensed examples · CaptchaLa is operated independently