服务端 API

你的服务端只需要调用两个接口:渲染表单前创建 intent,收到表单后兑换 token。其余接口都是可选的。

请求约定

  • 服务地址:https://captcha.moe(自己部署时换成你的服务地址)。
  • 所有请求都是 POST,请求体为 JSON,并带上 Content-Type: application/json
  • Secret key 放在请求头 Authorization: Bearer mc_sec_… 里,不要放在请求体中,也不要出现在浏览器里。
  • 建议设置 5 秒左右的超时。超时和网络错误按「暂时不可用」处理。
  • 失败时返回非 2xx 状态码和 {"error":"错误码"},全部错误码见错误码与排查
接口谁来调用用途
POST /intents你的服务端为一次操作创建验证许可(必需)
POST /siteverify你的服务端兑换访客提交的 token(必需)
POST /feedback你的服务端回传业务结果,例如确认是恶意注册(可选)
POST /grants你的服务端为已登录会话申请短时挑战豁免(可选,需部署开启)
POST /challenge/solve组件浏览器完成挑战,你不需要调用

POST /intents

在渲染表单之前调用,为「这一次操作」创建许可。把返回的 intent_id 保存到服务端记录里,再填进组件。

请求字段

字段类型说明
action字符串,必填业务动作名,1–64 位字母、数字、-_,例如 signup。兑换时必须一致。
nonce字符串,必填服务端生成的随机值,16–128 位字母、数字、-_。重试同一次创建时复用,得到同一个许可。
hostname字符串,必填表单所在域名,小写、不含协议和端口,必须在站点的允许域名里。
session字符串,可选你的服务端会话的 HMAC,64 位小写十六进制。用于把许可绑定到会话,不要发送原始会话 ID。
subject字符串,可选业务主体(例如账号)的 HMAC,64 位小写十六进制,用于按主体限流。不要发送邮箱或用户名。
trusted_grant_idUUID,可选使用短时挑战豁免时填入,见挑战豁免

响应字段

字段说明
intent_id许可 ID,填进组件的 data-intent,并保存到服务端记录
sitekey站点的 Site key,填进组件的 data-sitekey
actionhostname与请求相同,可用来核对
expires_at许可的截止时间(Unix 秒),创建后 5 分钟
POST https://captcha.moe/intents
Authorization: Bearer mc_sec_你的密钥
Content-Type: application/json

{
  "action": "signup",
  "nonce": "6f1c2a0e-0b8e-4c4f-9f5d-2d7c1e9a4b10",
  "hostname": "example.com"
}

POST /siteverify

收到表单后调用。只有 response 来自浏览器,其余字段都从你的服务端记录读取。返回 200 且各字段与记录一致,才执行业务。

请求字段

字段类型说明
response字符串,必填表单字段 moe-captcha-response 的值
intent_idUUID,必填创建时保存的 intent_id
actionhostname字符串,必填和创建 intent 时完全相同
idempotency_key字符串,必填幂等键,16–128 位字母、数字、-_。同一次提交重试时复用:10 分钟内返回同一结果,不重复扣费。

响应字段

字段说明
success成功时为 true;失败时不会返回 200,而是返回错误码
intent_idactionhostname请逐一与服务端记录比较,不一致就拒绝
decision_id这次验证的编号。保存下来,回传业务结果时要用
assessment目前固定为 passed,表示许可已通过,不是人类概率分数
POST https://captcha.moe/siteverify
Authorization: Bearer mc_sec_你的密钥
Content-Type: application/json

{
  "response": "表单里的 moe-captcha-response",
  "intent_id": "8c1f5d2e-3a47-4b1e-9c0d-5e6f7a8b9c0d",
  "action": "signup",
  "hostname": "example.com",
  "idempotency_key": "d3b07384-d9a0-4c7b-8b1e-2f6c1a9e5d44"
}

POST /feedback

可选。兑换成功后 7 天内,把业务上的最终判断告诉我们,例如这个注册后来被确认为恶意账号。反馈不会改变已有结果,也不会触发封禁。

字段说明
decision_id/siteverify 返回的 decision_id
event_id你生成的 UUID。网络重试时复用,不要换新的
outcomeconfirmed_abuselegitimateunknown
business_type业务类型,1–64 位字母、数字、-_
occurred_at业务结果发生的时间(Unix 秒),不早于兑换、不晚于现在
supersedes_event_id可选。修正之前的反馈时,指向最近一次的 event_id
请求
POST https://captcha.moe/feedback
Authorization: Bearer mc_sec_你的密钥
Content-Type: application/json

{
  "decision_id": "5b2e7c11-9d4a-4f0e-8a6b-1c3d5e7f9a2b",
  "event_id": "0e9d8c7b-6a5f-4e3d-2c1b-0a9f8e7d6c5b",
  "outcome": "confirmed_abuse",
  "business_type": "signup",
  "occurred_at": 1789400600
}

成功返回 {"accepted":true,"event_id":"…","revision":1,"expires_at":…}。字段规则和修正流程见回传业务结果

POST /grants

可选,需要部署开启。为已登录会话或刚完成过挑战的访客申请短时豁免,下一次验证可以跳过挑战,但仍需兑换和计费。字段、撤销(POST /grants/revoke)和错误处理见挑战豁免

组件调用的接口

POST /challengePOST /solve 由组件在浏览器里调用,按页面的来源(Origin)校验域名。你不需要、也不应该从服务端调用它们。它们的错误会通过组件的错误回调告诉你。

请求格式错误时

缺少字段或字段格式不对时,任何接口都返回 422 和出错的字段;请求体不是合法 JSON 返回 400 bad-request,没有使用 JSON 返回 415 unsupported-media-type,把 secret 放进请求体返回 422 secret-in-body

响应
HTTP/1.1 422 Unprocessable Entity

{
  "error": "bad-request",
  "field": "nonce"
}