3DS Verification Codes
Emitted when the issuing provider sends us a 3DS / OTP verification code callback.
Event Types
| Event | When Emitted |
|---|---|
card.3ds.received | Card 3DS / OTP verification code received |
Delivery Contract
- We send a
POSTrequest withapplication/jsonto your configured endpoint, with a 10-second timeout. - Any 2xx response acknowledges receipt. Non-2xx responses and timeouts trigger retries with backoff.
- Four request headers:
content-type·z-signature·z-event-id·z-event-type。 - Deduplicate by
z-event-id— the same event may be delivered more than once.
There are no amounts, asset codes, card number fragments or risk-control reasons. This is a security boundary: the webhook endpoint is your service, whose transport and storage we cannot guarantee.
The GET /v1/<resource>/{id} endpoint applies API key, scope and on-behalf-of checks. Fetch details using data.id;
do not use webhook payloads as the source of amounts for your ledger.
Event Details
card.3ds.received
Card 3DS / OTP verification code receivedEmitted after our issuing provider sends a 3DS / OTP verification code callback and it is successfully stored in card_3ds_events. Currently only two integrations produce this event: WAS and INT. data.id is the public card resource ID itself (crd_<id>); retrieval still uses GET /v1/cards/{id}. The actual verification code is exposed through three controlled additional fields in the event body:
otp_code: the short code for the user to enter manually.expires_at: the code’s expiration time, populated only when supplied by the upstream.application_id: for a card originating from an application, the publiccap_<id>identifies that application so you can associate it directly; cards without an originating application omit this field.
⚠ The event body does not expose our internal event_key or identify the upstream provider. Merchants should associate records using only the member, card, and application identifiers they already hold. ⚠ This is different from card.status.updated: receiving a code does not mean the card status changed. In particular, WAS continues attempting automatic activation after an activation code arrives. Check the subsequent card.activated event or retrieve card status to determine success; do not treat this event as successful activation.
{
"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"
}
}Signature Verification
The signature verification procedure is the same for all events. See Webhook Overview; use the Signature Debugger to compare signing strings character by character.