# Webhooks

Receive real-time events for API-created banking transfers.

Banking webhooks notify your server when an API-created transfer changes state. Register endpoints from your dashboard under **Developers → Banking**.

## Endpoint scope

Each webhook endpoint is **product-scoped**. An endpoint registered under Developers → Banking receives **only** banking events — it never receives card or checkout events. Each endpoint has its own verification token, and you can register more than one.

## Event types

| Event | When |
|-------|------|
| `banking.transfer.pending` | An API-created transfer is created or updated and still processing. |
| `banking.transfer.completed` | A transfer reaches a completed status. |
| `banking.transfer.failed` | A transfer fails. |
| `banking.transfer.cancelled` | A transfer is cancelled. |

## Payload

Every delivery wraps the transfer in a common envelope. `data` is the same object the [transfer endpoints](/docs/banking-transfers) return under `transfer`, so you can share status-handling code between the two.

```json
{
  "id": "evt_01HXR9...",
  "type": "banking.transfer.completed",
  "createdAt": "2026-06-25T12:01:20.000Z",
  "livemode": true,
  "data": {
    "id": "7b4f1f9c-7d92-4d12-a4aa-9c5b2f4f9b25",
    "object": "banking.transfer",
    "status": "completed",
    "direction": "debit",
    "rail": "pix",
    "description": "Acme Ltda supplier payout",
    "memo": "Invoice 1048",
    "sourceCurrency": "USDC",
    "sourceAmount": "18.82",
    "destinationCurrency": "BRL",
    "destinationAmount": "100.00",
    "fxRate": "5.31349628",
    "recipientId": "9a5b47c1-234d-4841-a5b8-d1b790f774be",
    "idempotencyKey": "pix-acme-1048",
    "createdAt": "2026-06-25T12:00:00.000Z",
    "updatedAt": "2026-06-25T12:01:20.000Z",
    "completedAt": "2026-06-25T12:01:20.000Z"
  }
}
```

## Verifying deliveries

Every request includes these headers:

- `X-Dolafy-Token` — your per-endpoint verification token, shown once when the endpoint is created.
- `Dolafy-Event-Id` — unique event id (also the body `id`).
- `Dolafy-Event-Type` — the event type.
- `Dolafy-Delivery-Id` — unique delivery id; retries of the same delivery reuse it.

Compare `X-Dolafy-Token` to the token you stored at creation and reject the request if it does not match. There is no HMAC signature — because the token is sent on every request, your endpoint must use HTTPS, keep the token secret, and avoid logging request headers. Rotate the token by recreating the endpoint.

## Delivery semantics

- Respond with a `2xx` quickly, then process the event asynchronously.
- Delivery is **best-effort and single-attempt** for banking events. There is no durable retry queue or replay endpoint.
- **Make your handlers idempotent** by `Dolafy-Event-Id` (or `Dolafy-Delivery-Id`), and reconcile anything you may have missed with [`GET /v1/banking/transfers/:id`](/docs/banking-transfers).
- Manual test deliveries sent from the dashboard include top-level `"test": true`. Never fulfil or move money from a test event.
