Setup
Yativo sends webhook notifications to your registered HTTPS endpoint via HTTP POST whenever a program event occurs. Each request is signed with HMAC-SHA256 so you can verify it genuinely came from Yativo.
Register your endpoint at the unified webhook endpoint. Card issuer events and general crypto events share the same service — subscribe to any combination.
curl -X POST 'https://crypto-api.yativo.com/api/v1/webhook/create-webhook' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://api.yourapp.com/webhooks/yativo",
"events": ["customer.funded", "customer.funding.failed", "transaction.authorized", "transaction.settled"],
"description": "Production card issuer webhook"
}'
{
"status": true,
"message": "Webhook created successfully",
"data": {
"webhook_id": "68241abc2f3d4e5f6a7b8c9d",
"url": "https://api.yourapp.com/webhooks/yativo",
"events": ["customer.funded", "customer.funding.failed", "transaction.authorized", "transaction.settled"],
"secret": "whsec_a8f3c2e1d4b7f9e2c5a3b6d8f1e4c7a2b5d8e1f4c7a2b5d8",
"created_at": "2026-05-12T14:00:00.000Z"
}
}
Store the secret securely — use a secrets manager or environment variable. The secret is also retrievable later via GET /v1/yativo-card/webhooks/:webhookId. If compromised, rotate it via POST /v1/yativo-card/webhooks/:webhookId/rotate-secret.
Pass "events": ["*"] to receive all event types. Other management endpoints:
| Method | Path | Action |
|---|
GET | /v1/yativo-card/webhooks | List all subscriptions |
GET | /v1/yativo-card/webhooks/:webhookId | Get one subscription (returns secret) |
PUT | /v1/yativo-card/webhooks/:webhookId | Update URL, events, or enabled state |
DELETE | /v1/yativo-card/webhooks/:webhookId | Delete subscription |
POST | /v1/yativo-card/webhooks/:webhookId/rotate-secret | Rotate signing secret |
GET | /v1/yativo-card/webhooks/:webhookId/deliveries | Delivery history for one webhook |
GET | /v1/yativo-card/webhooks/deliveries/all | All deliveries across webhooks |
POST | /v1/yativo-card/webhooks/deliveries/:deliveryId/retry | Retry a failed delivery |
Event categories
| Category | Events |
|---|
| Master Wallet | Deposits, token swaps, customer funding |
| Customer Funding | Funds received or failed into a customer’s card wallet, balance updates |
| Card Lifecycle | Card created, activated, frozen, unfrozen, voided, lost, stolen, cancelled, deactivated |
| Card Transactions | Authorization, settlement, decline, reversal, refund |
Event reference
| Event | Trigger |
|---|
master_wallet.deposit | Funds received into your master wallet |
master_wallet.swap | Token swap submitted (e.g. USD → EUR) |
master_wallet.customer_funded | Master wallet debited to fund a customer |
customer.funded | Customer’s card wallet received funds |
customer.funding.failed | Funding transfer failed (wallet misconfigured, insufficient balance, or network error) |
customer.balance.updated | Customer’s card balance changed (after spend, top-up, or authorization) |
card.created | New card issued to a customer |
card.activated | Card activated |
card.frozen | Card frozen |
card.unfrozen | Card unfrozen |
card.voided | Card voided (permanently disabled) |
card.lost | Card reported lost |
card.stolen | Card reported stolen |
card.cancelled | Card cancelled |
card.deactivated | Card deactivated |
transaction.authorized | Card transaction authorized |
transaction.settled | Transaction settled |
transaction.declined | Transaction declined |
transaction.reversed | Transaction reversed |
transaction.refund.created | Refund created |
Payload structure
All webhook events share a common envelope. The data object contains event-specific fields. The event type is also sent in the X-Yativo-Event request header.
{
"id": "evt_1747058400000_abc123",
"type": "customer.funded",
"created_at": "2026-05-12T14:30:00.000Z",
"data": { ... }
}
Payload examples
master_wallet.deposit
You will receive this event twice for a single deposit: once immediately when funds are detected (processing), and again when settlement is confirmed (settled). The payload shape differs between the two states.
status: "processing" — fired as soon as the incoming deposit is detected.
{
"id": "evt_1747058400000_abc123",
"type": "master_wallet.deposit",
"created_at": "2026-05-12T14:00:00.000Z",
"data": {
"settlement_id": "dep_1745123456_2ea87af00de1",
"source_amount": 500.00,
"tx_hash": "5KtP3MzXYZABCDE1234567890abcdef12345678901234567890abcdef1234567",
"status": "processing"
}
}
status: "settled" — fired once the funds are settled into your master wallet.
{
"id": "evt_1747058520000_def456",
"type": "master_wallet.deposit",
"created_at": "2026-05-12T14:02:00.000Z",
"data": {
"settlement_id": "dep_1745123456_2ea87af00de1",
"source_amount": 500.00,
"settled_amount": 499.75,
"status": "settled"
}
}
master_wallet.swap
Fired when a token swap is submitted from your master wallet.
{
"id": "evt_1747058700000_def456",
"type": "master_wallet.swap",
"created_at": "2026-05-12T14:05:00.000Z",
"data": {
"swap_id": "0x4a1b2c3d...",
"from_token": "USD",
"to_token": "EUR",
"amount": 1000.00,
"expected_output": 921.50,
"status": "submitted"
}
}
customer.funded
Fired when a customer’s card wallet has been credited. The transfer_id can be looked up via Get Transfer.
{
"id": "evt_1747059000000_ghi789",
"type": "customer.funded",
"created_at": "2026-05-12T14:10:00.000Z",
"data": {
"transfer_id": "tx_1745128800_9fc12ab3e4d5",
"customer_id": "69f0bdf29a84752db9cc8ff9",
"amount": 50.00,
"currency": "USD",
"status": "completed"
}
}
customer.funding.failed
Fired when a funding transfer to a customer’s card wallet fails.
{
"id": "evt_1747059000000_fail01",
"type": "customer.funding.failed",
"created_at": "2026-05-12T14:10:00.000Z",
"data": {
"customer_id": "69f0bdf29a84752db9cc8ff9",
"yativo_card_id": "yativo_card_customer_8f9a...",
"amount": 50.00,
"currency": "USD"
}
}
master_wallet.customer_funded
Fired alongside customer.funded whenever your master wallet is debited. Includes remaining_balance when the transfer settles immediately; omitted when the balance updates asynchronously.
{
"id": "evt_1747059001000_mwf01",
"type": "master_wallet.customer_funded",
"created_at": "2026-05-12T14:10:00.000Z",
"data": {
"transfer_id": "tx_1745128800_9fc12ab3e4d5",
"customer_id": "69f0bdf29a84752db9cc8ff9",
"amount": 50.00,
"currency": "USD",
"status": "completed",
"remaining_balance": 114.98
}
}
card.frozen
Fired when a card is frozen, either by your program or by the customer.
{
"id": "evt_1747059600000_mno345",
"type": "card.frozen",
"created_at": "2026-05-12T14:20:00.000Z",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a...",
"card_id": "card_token_abc123",
"status": "Frozen",
"timestamp": "2026-05-12T14:20:00.000Z"
}
}
The card_id field in webhook events is the card token identifier. This may differ from the card_id returned by the Get Customer endpoint. Use yativo_card_id as the stable cross-reference between webhook events and API responses.
customer.balance.updated
Fired whenever the card provider reports a balance change — after a purchase authorization, settlement, top-up, or reversal. Provides the full balance breakdown so you can update your UI in real time without polling.
{
"id": "evt_1747060200000_stu901",
"type": "customer.balance.updated",
"created_at": "2026-05-12T14:30:00.000Z",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a...",
"ledger_balance": 45.23,
"available_balance": 38.50,
"pending_balance": 6.73,
"currency": "EUR",
"timestamp": "2026-05-12T14:30:00.000Z"
}
}
transaction.authorized
Fired when a card transaction is authorized at the point of sale. A customer.balance.updated event typically follows immediately.
{
"id": "evt_1747059300000_jkl012",
"type": "transaction.authorized",
"created_at": "2026-05-12T14:15:00.000Z",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a...",
"card_id": "card_token_abc123",
"transaction_id": "tx_9d8e7f...",
"type": "purchase",
"amount": 12.50,
"currency": "EUR",
"merchant": "Starbucks",
"merchant_category": "5812",
"merchant_city": "Paris",
"merchant_country": "FR",
"status": "AUTHORIZED",
"timestamp": "2026-05-12T14:15:00.000Z"
}
}
card.lost
Fired when a card is reported lost.
{
"id": "evt_1747059900000_pqr678",
"type": "card.lost",
"created_at": "2026-05-12T14:25:00.000Z",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a...",
"card_id": "card_token_abc123",
"status": "Lost",
"timestamp": "2026-05-12T14:25:00.000Z"
}
}
Signature verification
Every webhook request includes an X-Yativo-Signature header and an X-Yativo-Timestamp header. The event type is also in the X-Yativo-Event header and the unique delivery ID in X-Yativo-Delivery-Id. Verify signature and timestamp before processing the event.
The signature is computed over the raw request body (the exact JSON bytes received), prefixed with the timestamp.
const crypto = require('crypto');
// Use express.raw({ type: 'application/json' }) so req.body is a Buffer, not a parsed object.
// req.headers['x-yativo-signature'] — the HMAC signature
// req.headers['x-yativo-timestamp'] — Unix timestamp (string)
function verifyWebhook(rawBody, signature, timestamp, secret) {
if (!signature || !timestamp) return false;
// Reject replays older than 5 minutes
if (Math.abs(Date.now() / 1000 - parseInt(timestamp, 10)) > 300) return false;
const signed = `${timestamp}.${rawBody.toString('utf8')}`;
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(signed).digest('hex');
try {
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
} catch {
return false;
}
}
Always verify the signature before trusting the payload. Use express.raw({ type: 'application/json' }) (not express.json()) so you have the raw bytes for verification.
Retry policy
Yativo retries failed webhook deliveries using exponential backoff. Respond with any HTTP 2xx status code to acknowledge receipt and prevent retries.
| Attempt | Delay after previous attempt |
|---|
| 1 (initial) | — |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours |
| 7 | 24 hours |
After 7 failed attempts the delivery is marked permanently failed — no further automatic retries. You can manually replay individual deliveries via POST /v1/yativo-card/webhooks/deliveries/:deliveryId/retry.
If your endpoint fails 100 consecutive deliveries, Yativo will automatically disable the subscription to protect your program’s event queue. Re-enable it via PUT /v1/yativo-card/webhooks/:webhookId with { "enabled": true } after fixing the issue.
To avoid processing duplicate events, use the top-level id field (e.g. evt_1747058400000_abc123) as an idempotency key. The X-Yativo-Delivery-Id header carries the delivery record ID (a separate identifier used to retry individual deliveries via the API).