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

# TED webhooks

> React to TED transfer events in real time with webhooks — completed, failed, chargeback, and reconciliation notifications without polling.

Webhooks let your system react to transfer events in real time — no polling required. When a transfer completes, fails, or requires attention, your endpoint receives a notification automatically.

## Available events

***

| Event                              | When it fires                                                               | Transfer types | Recommended action                                                                 |
| ---------------------------------- | --------------------------------------------------------------------------- | -------------- | ---------------------------------------------------------------------------------- |
| `transfer.initiated`               | Transfer record created after initiation is confirmed                       | TED OUT, P2P   | Update transfer status in your system; show "transfer in progress" to the customer |
| `transfer.processing`              | Midaz transaction hold succeeded; transfer advancing toward completion      | TED OUT, P2P   | Show customer that transfer is being processed                                     |
| `transfer.rejected`                | JD SPB returned a 4xx rejection (invalid data, rule violation)              | TED OUT        | Notify customer that transfer was rejected; funds already released                 |
| `transfer.completed`               | Transfer settled successfully                                               | P2P            | Notify customer; generate receipt; update balance display                          |
| `transfer.failed`                  | Transfer reached a terminal failure due to 5xx error or timeout from JD SPB | TED OUT        | Notify customer that transfer did not go through; refund if needed                 |
| `transfer.cancelled`               | Transfer cancelled by customer before processing                            | TED OUT, P2P   | Confirm cancellation to customer; release any UI locks                             |
| `transfer.incoming.completed`      | Inbound TED received, recipient found, credit applied                       | TED IN         | Notify recipient that funds have arrived; update balance display                   |
| `transfer.incoming.chargeback`     | Chargeback message received for a previously completed TED IN (STR0010R2)   | TED IN         | Freeze the credited amount; initiate review with your compliance team              |
| `transfer.reconciliation_required` | Inconsistency detected during deduplication                                 | TED IN         | Flag for manual reconciliation; do not credit until resolved                       |

<Note>
  For TED OUT, the `transfer.completed` event is not yet emitted. TED OUT completion is confirmed asynchronously by SPB and will be supported in a future release. Until then, monitor TED OUT status via the [Get Transfer](/en/reference/midaz/plugins/ted/retrieve-transfer) endpoint or the reconciliation endpoint.
</Note>

## Configuring webhooks

***

Webhooks are configured per organization, so each tenant can have its own endpoint and secret. Set your `webhookUrl` (must be HTTPS) and `webhookSecret` through the admin configuration. For setup instructions, see [TED configuration](/en/midaz/plugins/ted/ted-configuration).

## Payload structure

***

All webhook events share the same envelope. Envelope fields are stable across event types; the per-event payload sits inside `payload`.

| Field           | Type                  | Notes                                                                           |
| --------------- | --------------------- | ------------------------------------------------------------------------------- |
| `eventId`       | string (UUID)         | Unique id of this event emission. Use it for at-least-once dedupe on your side. |
| `version`       | string                | Envelope schema version. Currently `v1`.                                        |
| `type`          | string                | Event type, e.g. `transfer.completed`.                                          |
| `tenantId`      | string (UUID)         | Organization that owns the transfer.                                            |
| `transferId`    | string (UUID)         | Present for transfer-scoped events; omitted for tenant-scoped events.           |
| `correlationId` | string                | Correlates the chain of events produced by one originating request.             |
| `causationId`   | string                | Optional. Id of the event that caused this one (for chained workflows).         |
| `occurredAt`    | string (RFC3339, UTC) | When the event occurred on the plugin side.                                     |
| `payload`       | object                | Event-specific fields. Schema depends on `type` (see below).                    |
| `metadata`      | object                | Optional string-to-string map carrying tracing and routing hints.               |

Here is an example of `transfer.completed` for a P2P transfer:

```json theme={null}
{
  "eventId": "019c96a0-ee10-7fff-aaaa-1111aaaa2222",
  "version": "v1",
  "type": "transfer.completed",
  "tenantId": "019c96a0-0a98-7287-9a31-786e0809c769",
  "transferId": "019c96a0-ab10-7cde-f1a2-0e1f2a3b4c5d",
  "correlationId": "019c96a0-aa10-7abc-d1e2-8c9d0e1f2a3b",
  "occurredAt": "2026-01-21T17:35:00Z",
  "payload": {
    "status": "COMPLETED",
    "transferType": "P2P",
    "midazTransaction": "019c96a0-cd10-7eee-bbbb-3333bbbb4444",
    "confirmationNumber": "20260121001"
  },
  "metadata": {}
}
```

The `payload` shape is per-event-type. For `transfer.completed`, the fields are `status`, `transferType`, `midazTransaction`, and `confirmationNumber` (each emitted only when set). To retrieve amounts, fees, recipient details, or timestamps, fetch the transfer via [Get Transfer](/en/reference/midaz/plugins/ted/retrieve-transfer) using the envelope's `transferId`.

<Note>
  See the API Reference for full payload schemas for each event type.
</Note>

## Handling delivery failures

***

If your endpoint does not respond with a 2xx status within 5 seconds (`WEBHOOK_TIMEOUT_MS=5000`), the event is retried automatically with exponential backoff and full jitter. The plugin makes up to `WEBHOOK_MAX_RETRIES` attempts in total (default `3`), with a base delay of `WEBHOOK_RETRY_BACKOFF_MS` (default `500` ms) doubled on each retry:

| Attempt | Delay before this attempt             |
| ------- | ------------------------------------- |
| 1       | Immediate                             |
| 2       | Random in `[0, 1000 ms]` (base × 2^1) |
| 3       | Random in `[0, 2000 ms]` (base × 2^2) |

After 3 unsuccessful attempts, the event moves to a dead-letter queue (DLQ). Set up alerts on the DLQ to catch persistent delivery failures before they affect your operations. Tune `WEBHOOK_MAX_RETRIES` and `WEBHOOK_RETRY_BACKOFF_MS` if your endpoint needs a longer or shorter retry budget.

To ensure reliable delivery: respond within 5 seconds, use HTTPS with a valid certificate, and return 200 even for events you choose to ignore. Offload any heavy processing to a background queue — keep your webhook handler fast.

## Idempotency

***

<Note>
  Your endpoint may receive the same event more than once. Use the `transferId` (and the event name) to deduplicate: if you have already processed that combination, return 200 and take no further action.
</Note>

## For developers

***

For signature validation code (JavaScript, Python, Go), retry implementation, and the full integration checklist, see the [TED developer guide](/en/midaz/plugins/ted/ted-developer-guide).
