卡发行 › Webhook
3DS 验证码
发卡上游把 3DS / OTP 验证码回调给我方时发送。
事件类型
| 事件 | 什么时候发 |
|---|---|
card.3ds.received | 卡片 3DS / OTP 验证码已收到 |
投递约定
- 我方向你配置的端点发
POST,application/json,超时 10 秒。 - 回任意 2xx 即视为收到。 非 2xx 或超时会按退避重投。
- 请求头四个:
content-type·z-signature·z-event-id·z-event-type。 - 按
z-event-id去重 —— 同一条事件可能到达多次。
事件体只带 ID 与状态
没有金额、没有资产代码、没有卡号的任何片段、没有风控原因。这不是省字节 ——
webhook 端点是你的服务,我方没有办法保证它的传输与存储;
而 GET /v1/<资源>/{id} 那条路径上有 API Key、scope、
代理会员三层校验。要详情就拿 data.id 回查,
别指望从事件体里读出金额来记账。
逐条
card.3ds.received
卡片 3DS / OTP 验证码已收到什么时候发
发卡上游把 3DS / OTP 验证码回调给我方、并成功落库到 card_3ds_events 之后。目前生产者只有两条:WAS 与 INT。data.id 直接就是公开卡资源 ID(crd_<id>),拿它回查仍走 GET /v1/cards/{id};真正给你展示验证码的,是事件体里受控附带的三个字段:
otp_code:给用户手输的短码;expires_at:这条码的失效时间(上游有给才会带值)。application_id:若这张卡来自申请单,会带公开格式的cap_<id>,方便你直接关联自己那笔开卡申请;没有申请单来源的卡则不带这个字段。
⚠ 事件体不会暴露我方内部 event_key,也不会告诉你上游 provider 是谁;商户侧应该只依赖自己已经持有的会员/卡/申请单坐标做关联。⚠ 这条事件与 card.status.updated 不是一回事:收到验证码并不等于卡状态发生变化;尤其 WAS 会在收到激活码后继续尝试自动激活,成不成要看后续 card.activated或卡状态回查,别把这条事件当成“激活成功”。
事件体
{
"event_id": "evt_8dc2a13d65904ef29c5ea2f2fe7a1dc2",
"event_type": "card.3ds.received",
"created_at": "2026-09-07T11:38:19Z",
"merchant_id": "acme",
"livemode": true,
"data": {
"object": "card",
"id": "crd_e70b3d41-5a28-4c96-91f0-6b2a8c05d7e3",
"external_member_id": "u_88123",
"status": "received",
"status_version": 13,
"application_id": "cap_3882c371-572f-4d5a-af08-f61fc0964de9",
"otp_code": "54695634",
"expires_at": "2026-09-07T11:38:19.549Z"
}
}验签
验签方式与所有事件一致,见 Webhook 概览; 可以用签名调试器逐字符比对签名串。