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

# Webhooks

> Set up Breet API webhooks to receive real-time notifications for crypto deposits, withdrawals, and trade events. Includes payload examples and security best practices.

Breet sends webhook notifications to your server whenever important events occur, such as incoming crypto deposits or withdrawal status changes. Your application can listen for these events and respond accordingly.

<Note>
  **Outgoing delivery logs & manual resend:** To list stored deliveries, view attempt history for one event, or trigger a one-off resend by trade/withdrawal reference, use the **Webhooks** group in the **API reference** tab (endpoints under `/transactions/webhooks`). This guide covers **incoming** payloads and verification on your server.
</Note>

## Crypto wallet deposit webhooks

These webhooks fire whenever a wallet address receives crypto assets. You will receive events for the following transaction states:

| Event             | Description                                                                                                                                                                                                     |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trade.pending`   | An incoming crypto transaction has been detected on the blockchain but has not yet been fully confirmed or processed.                                                                                           |
| `trade.completed` | The transaction is fully confirmed, has passed all checks, and your account has been credited.                                                                                                                  |
| `trade.flagged`   | The transaction is confirmed on-chain but below the asset's minimum deposit amount. Funds are held and not credited. See [how flagged deposits are resolved](/deposits#what-happens-when-a-deposit-is-flagged). |

### Payload example

```json theme={null}
{
  "id": "692f91aa729255932afe9078",
  "asset": "SOL_TEST",
  "feePercentage": 1.5,
  "feeAmountInUsd": 0.32,
  "rate": 1600,
  "conversionRate": 1
  "cryptoAmount": 0.00025406,
  "amountInUSD": 21.379427842514175,
  "flagFeeUSD": 0,
  "vaultId": "121",
  "senderAddress": "bc1qf43tdrym26qlz8rg06f88wg35n27uhcf29zs4f",
  "destinationAddress": "6DKYpZfd86BUDTjPe4E3JEGwnYW99KU3NDazk7BjpN8V",
  "destinationDescription": "Partner_testingizzy",
  "txHash": "aa801188ukdjfhdbf3771dfdf86388b8b694a2ac0226748346y34kbc3",
  "status": "completed",
  "confirmations": 3,
  "note": "",
  "isWrongAssetDeposit": true,
  "event": "trade.completed",
  "createdAt": 1764614655493,
  "updatedAt": 1764616198265,
  "index": 19,
  "blockInfo": {
    "blockHeight": "926040",
    "blockHash": "0000000000000000000158f293cda641e08a144673dc03814b187e8db758c929"
  }
}
```

### Payload fields

| Field                    | Type      | Description                                                                                                                                                                                                                           |
| ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                     | string    | Unique identifier for the transaction.                                                                                                                                                                                                |
| `asset`                  | string    | The crypto asset involved (e.g., `ETH`, `BTC`).                                                                                                                                                                                       |
| `feePercentage`          | number    | Breet's platform fee rate applied to the trade, expressed as a percentage (e.g., `0.5` means 0.5%).                                                                                                                                   |
| `feeAmountInUsd`         | number    | The platform fee amount in USD, calculated as `(feePercentage / 100) x amountInUSD`.                                                                                                                                                  |
| `cryptoAmount`           | number    | Amount of crypto transferred.                                                                                                                                                                                                         |
| `amountInUSD`            | number    | Value of the transaction in USD.                                                                                                                                                                                                      |
| `flagFeeUSD`             | number    | Fee applied for trades below minimum asset requirement. Initially `0`, may be updated later.                                                                                                                                          |
| `vaultId`                | string    | ID of the vault handling the transaction.                                                                                                                                                                                             |
| `rate`                   | number    | The NGN per USD rate.                                                                                                                                                                                                                 |
| `conversionRate`         | number    | The NGN to GHS rate applied for GHS transactions, always `1` for NGN.                                                                                                                                                                 |
| `senderAddress`          | string    | Wallet address of the sender.                                                                                                                                                                                                         |
| `destinationAddress`     | string    | Wallet address receiving the funds.                                                                                                                                                                                                   |
| `destinationDescription` | string    | Optional description for the recipient.                                                                                                                                                                                               |
| `txHash`                 | string    | Blockchain transaction hash.                                                                                                                                                                                                          |
| `status`                 | string    | Transaction status (`pending`, `completed`, `flagged`).                                                                                                                                                                               |
| `confirmations`          | number    | Number of blockchain confirmations.                                                                                                                                                                                                   |
| `note`                   | string    | Optional note associated with the transaction.                                                                                                                                                                                        |
| `isWrongAssetDeposit`    | boolean   | Present and set to `true` **only** on the `trade.pending` event when this deposit was recovered from a wrong-asset send (e.g. ETH sent to a USDT address). Omitted from all other payloads. See [Wrong asset](/deposits#wrong-asset). |
| `event`                  | string    | Webhook event type (`trade.completed`, `trade.pending`, `trade.flagged`).                                                                                                                                                             |
| `createdAt`              | timestamp | Transaction creation timestamp (milliseconds).                                                                                                                                                                                        |
| `updatedAt`              | timestamp | Last update timestamp (milliseconds).                                                                                                                                                                                                 |
| `index`                  | number    | Internal index for ordering transactions.                                                                                                                                                                                             |
| `blockInfo.blockHeight`  | string    | Block height in the blockchain.                                                                                                                                                                                                       |
| `blockInfo.blockHash`    | string    | Hash of the block containing this transaction.                                                                                                                                                                                        |

### Auto-settlement fields

When a bank account is linked to a wallet address and auto-settlement is enabled, the webhook payload includes additional fields. For a full explanation of how auto-settlement works, see the [Auto-settlement](/auto-settlement) guide.

| Field           | Type   | Description                                                                               |
| --------------- | ------ | ----------------------------------------------------------------------------------------- |
| `markupPercent` | number | The percentage markup configured on your integration (e.g. `2.5`, optionally set by you). |
| `markupAmount`  | number | The absolute amount deducted as markup from the converted local currency amount.          |
| `amountSettled` | number | The final amount paid out to the linked bank account, after markup deduction.             |

<Info>
  If a markup percentage is set, it is deducted from the transaction amount before the final payout is calculated. For example, if a trade amount is 1,000 USD and a 5% markup is applied, 50 USD is deducted and the settlement is calculated based on 950 USD.
</Info>

### Behavior notes

* The webhook may send **multiple events** for the same transaction as its status changes. For example, a transaction may first trigger `trade.pending`, then later `trade.completed`.
* The `confirmations` field indicates how many blockchain confirmations the transaction has received. This is especially important for `trade.completed` events.
* For auto-settlement trades, withdrawal events are also sent and the related trade ID is included in the notification response.

***

## Address creation webhook

This webhook fires as a fallback when a wallet address is successfully generated. It confirms the address is live and ready to receive deposits.

| Event                   | Description                                                                                                          |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `trade.address.created` | A wallet address has been generated and is ready to receive deposits. Sent as a fallback alongside the API response. |

### Payload example

```json theme={null}
{
  "event": "trade.address.created",
  "id": "6a1e1281ab08f50ad3127259",
  "address": "TB3yDFJXFKM2BySqhCPgyRuSzVkSR2CVam",
  "asset": "TRX_TEST",
  "label": "unique-ref"
}
```

### Payload fields

| Field     | Type   | Description                                                            |
| --------- | ------ | ---------------------------------------------------------------------- |
| `event`   | string | Always `trade.address.created`.                                        |
| `id`      | string | Unique identifier for the generated address record.                    |
| `address` | string | The wallet address that was created.                                   |
| `asset`   | string | The asset identifier the address was generated for (e.g., `TRX_TEST`). |
| `label`   | string | The label passed when the address was generated.                       |

***

## Fiat/Crypto withdrawal webhooks

These webhooks fire whenever a withdrawal is created or when its status changes.

| Event                  | Description                                                                                                                    |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `withdrawal.pending`   | The withdrawal request has been received and is being processed.                                                               |
| `withdrawal.completed` | The withdrawal has been successfully processed and paid out.                                                                   |
| `withdrawal.reversed`  | The withdrawal was sent to the payment provider but the provider returned a failure. Funds are refunded to your wallet.        |
| `withdrawal.rejected`  | The withdrawal was rejected during internal review before being sent to a payment provider. Funds are refunded to your wallet. |

### Payload example

```json theme={null}
{
  "id": "6968ed1398fea49e805363bb",
  "event": "withdrawal.pending",
  "amount": 1000,
  "originalAmount": 1000,
  "currency": "usd",
  "status": "pending",
  "txHash": "0x123abcdef",
  "reference": "6968ed1398fea49e805363bb",
  "fee": 10,
  "meta": {
    "walletAddress": "14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5",
    "network": "SOL",
    "token": "USDT",
    "symbol": "USDT",
    "avatar": "https://assets.breet.io/token-network-assets/USDT_SOL.png",
    "label": "",
    "txLink": "https://solscan.io/tx/"
  },
  "reason": "",
  "createdAt": "2026-01-15T13:35:15.967Z",
  "updatedAt": "2026-01-15T13:35:15.967Z"
}
```

### Payload fields

| Field                 | Type              | Description                                                                                                      |
| --------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- |
| `id`                  | string            | Unique identifier for the withdrawal request.                                                                    |
| `event`               | string            | Webhook event type (`withdrawal.pending`, `withdrawal.completed`, `withdrawal.reversed`, `withdrawal.rejected`). |
| `txHash`              | string            | Blockchain transaction hash (only present on completed transactions).                                            |
| `amount`              | number            | Net amount to be withdrawn after fees.                                                                           |
| `originalAmount`      | number            | Original withdrawal amount before fees were applied.                                                             |
| `payoutAmount`        | number            | The actual fiat amount paid out (after markup deduction for business).                                           |
| `currency`            | string            | Currency of the withdrawal (e.g., `usd`).                                                                        |
| `status`              | string            | Current withdrawal status (`pending`, `completed`, `reversed`, `rejected`).                                      |
| `reference`           | string            | Unique reference for the withdrawal. Always the same value as `id`. We recommend using `id` instead.             |
| `trade`               | string            | Trade ID (if withdrawal was initiated from a trade).                                                             |
| `fee`                 | number            | Fee charged for processing the withdrawal.                                                                       |
| `meta`                | object            | Additional metadata related to the withdrawal destination.                                                       |
| `meta.type`           | string            | Withdrawal destination type (e.g., `nuban`, `crypto`).                                                           |
| `meta.bankId`         | string            | Bank identifier for NUBAN withdrawals.                                                                           |
| `meta.bankName`       | string            | Name of the destination bank.                                                                                    |
| `meta.accountName`    | string            | Verified bank account holder name.                                                                               |
| `meta.account`        | string            | Internal account reference ID.                                                                                   |
| `meta.accountNumber`  | string            | Bank account number (NUBAN).                                                                                     |
| `meta.autoSettlement` | boolean           | Whether the withdrawal is processed automatically.                                                               |
| `meta.narration`      | string            | Transfer narration or description shown on bank statement.                                                       |
| `meta.fee`            | number            | Withdrawal fee charged for the transaction.                                                                      |
| `meta.walletAddress`  | string            | Destination wallet address for crypto withdrawals.                                                               |
| `meta.network`        | string            | Blockchain network used for the withdrawal (e.g., `SOL`).                                                        |
| `meta.token`          | string            | Token being withdrawn (e.g., `USDT`).                                                                            |
| `meta.symbol`         | string            | Token symbol.                                                                                                    |
| `meta.avatar`         | string            | URL to the token or network asset icon.                                                                          |
| `meta.label`          | string            | Optional label or description for the withdrawal destination.                                                    |
| `meta.txLink`         | string            | Base URL for viewing the transaction on a blockchain explorer.                                                   |
| `reason`              | string            | Reason for rejection or reversal (empty if not applicable).                                                      |
| `createdAt`           | string (ISO 8601) | Timestamp when the withdrawal was created.                                                                       |
| `updatedAt`           | string (ISO 8601) | Timestamp of the most recent status update.                                                                      |

### Behavior notes

* A single withdrawal may trigger **multiple webhook events** as its status progresses.
* `withdrawal.pending` is always sent first.
* `txHash` will not be present until the withdrawal is completed.
* Always rely on the `event` and `status` fields to determine the current state of a withdrawal.

***

## Webhook verification

To ensure the security and authenticity of incoming webhook notifications, Breet provides multiple layers of verification.

### IP whitelisting

All webhook requests originate from Breet's secure servers. Verify that incoming requests come from one of the following IP addresses:

```
46.101.201.155
46.101.225.109
46.101.225.97
46.101.225.251
159.89.20.62
```

Requests from any other IP addresses should be considered untrusted and ignored.

### Webhook secret

Each webhook endpoint is configured with a **webhook secret**, visible in your dashboard (Go to **Settings → For Developer**) under the **Webhook Verification Secret Key**. The secret is included in every webhook request as a header:

```
x-webhook-secret: <your-webhook-secret>
```

To verify a webhook request:

1. Retrieve the `x-webhook-secret` header from the incoming request.
2. Compare it against the secret configured in your dashboard.
3. Only process the request if the secrets match.

<Warning>
  Keep your webhook secret secure. Do not expose it in public repositories, client-side code, or logs.
</Warning>

### Recommended verification flow

1. Check the request IP against the allowed Breet IPs.
2. Validate the `x-webhook-secret` header against the configured secret.
3. Only process the payload if both checks pass.
4. As an extra check, call [Fetch Transaction by ID](/api-reference/transactions/fetch-transaction-by-id) or [Fetch Withdrawal by ID](/api-reference/withdrawals/fetch-withdrawal-by-id) to confirm the transaction exists on Breet before taking any action.

***

## Webhook retries

If your server does not respond with a successful **2xx** status code, Breet automatically retries delivering the webhook using an exponential backoff schedule:

| Attempt   | Delay     |
| --------- | --------- |
| 1st retry | 1 minute  |
| 2nd retry | 5 minutes |
| 3rd retry | 1 hour    |
| 4th retry | 4 hours   |
| 5th retry | 8 hours   |
| 6th retry | 12 hours  |
| 7th retry | 24 hours  |

After the final retry (24 hours), the webhook attempt is marked as **permanently failed**.

### Retry conditions

Retries occur when:

* Your webhook endpoint returns any **non-2xx** HTTP status code (including 3xx, 4xx, or 5xx).
* Your webhook endpoint times out.
* Your server is unreachable.

Breet **does not** retry events where your server returns **2xx**, even if the response body contains an error.

### Best practices

* Return a **2xx** status code as soon as your server receives and accepts the webhook.
* **Handle duplicate deliveries.** Breet may deliver the same event more than once during retries. Use the `id` and `event` fields together to detect duplicates and ensure your processing logic is idempotent.
* Log all received events and failures to aid debugging.

***

## Resending webhooks

If your server missed a webhook or you need to replay events for debugging, Breet lets you inspect delivery history and trigger manual resends. All outgoing webhook events are persisted for **7 days**.

You can resend webhooks in two ways:

* **From the dashboard** — Go to **Settings → For Developer → Webhook Logs** to view all outgoing events, inspect delivery statuses, and resend any event with a single click.
* **Via the API** — Use the endpoints below to programmatically list, inspect, and resend webhook events.

<Note>
  The API endpoints below require an active integration with API access (VIP partners). For full request/response schemas, see the [Webhooks API reference](/api-reference/webhooks).
</Note>

### List delivery history

Retrieve a paginated list of all outgoing webhook events sent to your endpoint.

```bash theme={null}
GET /transactions/webhooks
```

You can filter results using optional query parameters:

| Parameter   | Type   | Description                                                           |
| ----------- | ------ | --------------------------------------------------------------------- |
| `page`      | number | Page number for pagination.                                           |
| `reference` | string | Filter by a specific trade or withdrawal ID.                          |
| `status`    | string | Filter by delivery outcome: `delivered` or `failed`.                  |
| `eventName` | string | Filter by event type (e.g., `trade.completed`, `withdrawal.pending`). |

### View a single event

Fetch full details for a specific webhook event, including every delivery attempt with timestamps and HTTP status codes.

```bash theme={null}
GET /transactions/webhooks/{id}
```

The response includes the `attempts` array, which records each delivery try with the response status code and timestamp — useful for diagnosing endpoint failures.

### Resend by reference

Trigger an immediate redelivery of **all** webhook events associated with a given trade or withdrawal reference.

```bash theme={null}
POST /transactions/webhooks/resend/{reference}
```

The `reference` is the trade or withdrawal document ID (the same value as `id` in your webhook payloads). The response returns the result of each resend attempt:

```json theme={null}
{
  "success": true,
  "message": "webhook resend attempted",
  "data": [
    {
      "id": "67a1b2c3d4e5f67890123456",
      "status": "delivered"
    },
    {
      "id": "67a1b2c3d4e5f67890123457",
      "status": "failed",
      "error": "webhook delivery failed"
    }
  ]
}
```

### When to resend

* Your server was down during the original delivery and all automatic retries have been exhausted.
* You deployed a bug fix and need to replay events that previously failed processing.
* You want to verify your webhook handler is working correctly in a staging environment.

<Warning>
  Resent webhooks contain the same payload as the original event. Make sure your processing logic is **idempotent** — use the `id` and `event` fields to detect duplicates and avoid processing the same event twice.
</Warning>
