card.failed — delivered when card issuance fails.When it fires#
The Issue Card endpoint returned status: PENDING, but the card network subsequently rejected
the request. The card will not become usable and no further events are sent for it.To retry, issue a new card with a fresh externalId.Payload#
Envelope#
| Field | Type | Description |
|---|
eventId | string | Unique per event. Deduplicate on this value |
eventType | string | Always card.failed |
version | string | Payload schema version. Additive changes do not bump it |
occurredAt | string | When the event happened, not when it was delivered (ISO 8601) |
data | object | The card, see below |
data#
| Field | Type | Description |
|---|
cardNo | string | PIK card number |
cardholderNo | string | PIK cardholder number this card belongs to |
maskedCardNumber | string | null — a failed card has no card number to show |
status | string | FAILED for this event |
cardLimit | string | Cumulative spending ceiling that was requested |
availableLimit | string | null — a failed card has no spendable balance |
currency | string | Settlement currency |
label | string | Your label for the card |
externalId | string | Your own identifier |
createTimeUtc | string | Creation time (UTC) |
Example#
{
"eventId": "evt_01J9X8ZQ4T2M",
"eventType": "card.failed",
"version": "1.0",
"occurredAt": "2026-08-11T02:16:44Z",
"data": {
"cardNo": "CD260811X9Y8Z7",
"cardholderNo": "CH260811A1B2C3",
"maskedCardNumber": null,
"status": "FAILED",
"cardLimit": "500.00",
"availableLimit": null,
"currency": "USD",
"label": "Ads spend - Q3",
"externalId": "card-req-4471",
"createTimeUtc": "2026-08-11T02:16:02Z"
}
}
Verifying the signature#
Three headers accompany every delivery:| Header | Value |
|---|
X-Webhook-Event | Event category, always ISSUING for this event |
X-Webhook-Event-Type | The specific event type, see above |
X-Webhook-Signature | HMAC-SHA256 signature, lowercase hex |
X-Webhook-Signature = hex_lower( HMAC_SHA256( appSecret, rawBody ) )
The signed content is the raw request body only, with no timestamp and no separator. The signing
key is your appSecret — there is no separate webhook secret.1.
Sign the raw bytes of the request body, before any JSON parsing.
2.
Compare in constant time.
3.
Nothing time-based is signed, so a captured delivery stays replayable — deduplicating on
eventId is mandatory, not optional.
Delivery#
Return any 2xx within 10 seconds to acknowledge.
Failed deliveries are retried on a fixed interval: 5 attempts, 5 minutes apart (about
20 minutes in total), after which the event is marked exhausted and never retried again.
This endpoint receives Issuing events only; still return 2xx for event types you do not handle.
Delivery is at least once — deduplicate on eventId.
Ordering is not guaranteed — use occurredAt to decide which version is newer.
See the Webhooks guide for verification code samples and recommended
handling.Modified at 2026-09-30 09:27:06