> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.imbawallet.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> HMAC-signed outbound events and idempotency by event_id.

# Webhooks

IMBA POSTs terminal (and smoke-test) events to the HTTPS URL configured for your tenant.

## Delivery semantics

* **At-least-once** delivery
* Idempotency key: `event_id` (UUID). Duplicate delivery → return `200` without applying twice
* Signature header: `X-IMBA-Signature`
* Content-Type: `application/json`

Allowlist IMBA egress IPs (list from onboarding / ops) on your firewall if required.

## Signature

```
X-IMBA-Signature: hex(hmac_sha256(<your_webhook_secret>, raw_body))
```

Verify against the **raw** request body bytes before JSON parsing. Use the HMAC secret you registered with IMBA. Constant-time compare recommended.

## Envelope

```json theme={null}
{
  "event_id": "019d0130-aaaa-7bbb-8ccc-ddddeeeeffff",
  "event": "card_issue.status_changed",
  "occurred_at": "2026-07-10T09:28:00.000Z",
  "data": {
    "ext_id": "card-issue-20260710-003",
    "order_id": "019d0127-fd3c-78cc-ac8e-e36927c03535",
    "ref_id": "019d0127-fd3c-78cc-ac8e-e36927c03535",
    "status": "completed",
    "document_status": "done",
    "card_id": "00112233445566778899aabb",
    "http_status": "200"
  }
}
```

Field name is `event` (not `event_type`).

## Event types (v1)

| `event`                        | When                   |
| ------------------------------ | ---------------------- |
| `test.ping`                    | Oper smoke test        |
| `card_issue.status_changed`    | Card issue terminal    |
| `card_topup.status_changed`    | Card topup terminal    |
| `card_freeze.status_changed`   | Freeze terminal        |
| `withdrawal.status_changed`    | Withdrawal terminal    |
| `gift_purchase.status_changed` | Gift purchase terminal |
| `esim_purchase.status_changed` | eSIM purchase terminal |
| `esim_topup.status_changed`    | eSIM topup terminal    |

Not in v1: chargebacks, separate reconciliation settled events, unfreeze events.

## `data` fields

Minimum: `ext_id`, `status`, `document_status`. Often also `ref_id` / `order_id`, `card_id`, `http_status`, `error` / `message`, and when present `amount` / `currency` / `network` / `to_address` / `offer_id`.

### Secrets — never trust webhooks for these

| Secret                       | Where to fetch                          |
| ---------------------------- | --------------------------------------- |
| PAN / CVV / `card_encrypted` | `GET /partner/cards/{card_id}`          |
| Gift `epin` / codes          | `GET /partner/gift-cards/{purchase_id}` |
| eSIM LPA / QR                | `GET /partner/esims/{esim_id}`          |

Webhook payloads must not be treated as a source of card numbers, CVV, JWE, epin, or LPA.

## Smoke test

IMBA can send `test.ping` from the admin console. Expect HTTP `2xx`. Respond `200` for duplicate `event_id`.
