# AI-powered docs
Source: https://docs.breet.io/ai-powered-docs
Plug the Breet API docs directly into Cursor, VS Code, and any MCP-aware AI tool so your assistant answers from live documentation instead of guessing.
The Breet docs ship as an [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server at `https://docs.breet.io/mcp`. MCP is an open standard that lets AI coding tools fetch structured information from external sources. In Breet's case, that means every endpoint spec, payload field, error code, and webhook description on this site.
Once connected, your assistant pulls answers straight from these docs as you work. You can ask things like:
* "What's the request body for creating a withdrawal?"
* "Which webhooks fire when a deposit is flagged?"
* "Show me a curl example for generating a wallet address."
Every response is grounded in the docs as they exist right now, so your assistant stays in step with the latest schemas, fields, and error codes. Pick your tool below to get started.
Install in Cursor
Install in VS Code
Copy MCP URL
The Cursor and VS Code buttons open the app directly if installed. For other tools or manual setup, copy the MCP server URL: `https://docs.breet.io/mcp`
# Fetch Account Details
Source: https://docs.breet.io/api-reference/account/fetch-account-details
/api-reference/openapi.json get /users/fetch-integration
Retrieve integration details such as balances, wallets, platform fees, and preferences. Includes the current bank withdrawal fee per currency as `withdrawalFee`, and who absorbs it as `withdrawalFeeBearer`.
# Update Markup Percentage
Source: https://docs.breet.io/api-reference/account/update-markup-percentage
/api-reference/openapi.json put /users/markup-percent
Set a markup percentage that will be applied to your auto settled crypto transactions payout
# Fetch Deposit Assets
Source: https://docs.breet.io/api-reference/assets/fetch-deposit-assets
/api-reference/openapi.json get /trades/assets
Retrieves the full list of supported deposit/sell assets, available networks, and configuration settings.
# Fetch Withdrawal Assets
Source: https://docs.breet.io/api-reference/assets/fetch-withdrawal-assets
/api-reference/openapi.json get /payments/supported-assets-info
Retrieves the full list of supported withdrawal assets, available networks, rates, and withdrawal configuration settings.
# Add Bank
Source: https://docs.breet.io/api-reference/banks/add-bank
/api-reference/openapi.json post /payments/banks/add
This adds a validated NGN or GHS bank to your integration
# Delete bank
Source: https://docs.breet.io/api-reference/banks/delete-bank
/api-reference/openapi.json delete /payments/banks/{id}
Remove a saved bank account from your integration by ID. The bank will also be detached from all wallets associated with it.
# Fetch Bank By ID
Source: https://docs.breet.io/api-reference/banks/fetch-bank-by-id
/api-reference/openapi.json get /payments/integration-banks/{id}
Fetch a bank on your integration by ID
# Fetch Bank List
Source: https://docs.breet.io/api-reference/banks/fetch-bank-list
/api-reference/openapi.json get /payments/banks
Retrieve list of available banks
# Fetch Saved Banks
Source: https://docs.breet.io/api-reference/banks/fetch-saved-banks
/api-reference/openapi.json get /payments/integration-banks
Fetch banks on your integration
# Verify Bank Account
Source: https://docs.breet.io/api-reference/banks/verify-bank-account
/api-reference/openapi.json post /payments/banks/validate
Verify bank account
# Convert Fiat to USD
Source: https://docs.breet.io/api-reference/conversion/convert-fiat-to-usd
/api-reference/openapi.json post /payments/fiat-to-usd
Convert local fiat (NGN or GHS) balance to USD. Optionally provide a withdrawal address ID to automatically withdraw the converted USD to that address.
# Convert USD to Fiat
Source: https://docs.breet.io/api-reference/conversion/convert-usd-to-fiat
/api-reference/openapi.json post /payments/convert
Convert USD balance to local fiat (NGN or GHS). Optionally specify a saved bank to credit.
# Fetch Wallet Addresses
Source: https://docs.breet.io/api-reference/crypto-wallet/fetch-wallet-addresses
/api-reference/openapi.json get /trades/wallets
Retrieve all wallet addressess.
# Fetch Wallet By ID
Source: https://docs.breet.io/api-reference/crypto-wallet/fetch-wallet-by-id
/api-reference/openapi.json get /trades/wallets/{id}
Retrieve a wallet using its unique ID.
# Generate Wallet Address
Source: https://docs.breet.io/api-reference/crypto-wallet/generate-wallet-address
/api-reference/openapi.json post /trades/sell/assets/{id}/generate-address
Generates a permanent deposit wallet address for a specified asset. Each address is unique and reusable, so you only need to call this once per user per asset. Store the returned address and display it for future deposits. Optionally pass bank details and `autoSettlement` so incoming crypto can be paid out to that bank.
A `trade.address.created` webhook is sent as a fallback once the address is live, containing the address, asset, and label.
# Set Auto Settlement Status
Source: https://docs.breet.io/api-reference/crypto-wallet/set-auto-settlement-status
/api-reference/openapi.json put /trades/wallets/{id}/auto-settlement
Enable/Disable auto settlement for a wallet address
# Update Bank For Existing Wallet Address
Source: https://docs.breet.io/api-reference/crypto-wallet/update-bank-for-existing-wallet-address
/api-reference/openapi.json put /trades/wallets/{id}/bank
Update the bank account linked to an existing wallet address. Optionally set `autoSettlement` so incoming crypto to this address is paid out to that bank.
# API overview
Source: https://docs.breet.io/api-reference/introduction
Authenticate with the Breet API using header-based credentials. Learn about environments, base URL, response format, and security best practices.
The **Breet API** lets you accept crypto deposits, convert between assets, manage bank payouts, and track transactions programmatically. This page covers authentication, required headers, and response format.
***
## Authentication
All requests to our API must be authenticated. We use a secure, header-based authentication method built around the following credentials:
* **`x-app-id`**
* **`x-app-secret`**
These credentials uniquely identify your application and authorize access to protected endpoints.
Additionally, you must specify the environment you want to interact with by including:
* **`X-Breet-Env`**
This header determines whether your requests are routed to the **sandbox** or **production** environment.
### Accepted values for `X-Breet-Env`
* `sandbox`
* `production`
If this header is missing or invalid, your request will be rejected.
***
**The API base URL:** [https://api.breet.io/v1](https://api.breet.io/v1)
***
## Obtaining your credentials
You can generate and manage your API credentials directly from the **Developers** section of your dashboard:
1. Log in to your dashboard
2. Navigate to **Developers → API Credentials**
3. Generate or copy your:
* **App ID**
* **App Secret**
Your **App Secret** is extremely sensitive. Treat it like a password or private key. For a step-by-step walkthrough, see the [quickstart](/quickstart).
***
## Keeping your credentials secure
To maintain the security of your integration:
* Never expose your App Secret in frontend code, mobile applications, GitHub repositories, or client-side logs
* Store secrets in a secure storage system (e.g., environment variables, Vault, AWS Secrets Manager, GCP Secret Manager)
* Rotate your credentials periodically as part of your security best practices
* If you suspect a leak or unauthorized access:
* Immediately **regenerate your App Secret** from the dashboard.
* The previous secret will be invalidated automatically.
This ensures only authorized systems can access the Breet API.
***
## Authentication best practices
* Use **server-to-server communication** whenever possible
* Avoid logging secrets in plaintext
* Ensure all requests are made over **HTTPS**
* Always include the correct **`X-Breet-Env`** header in every request
***
## Response format
All API responses follow a consistent JSON structure:
```json theme={null}
{
"success": true,
"message": "Description of the result",
"data": { ... },
"meta": { ... }
}
```
* **`success`**: `true` for successful requests, `false` for errors.
* **`message`**: A human-readable description of the result.
* **`data`**: The response payload (object, array, or empty).
* **`meta`**: Metadata such as pagination info.
For full details on error handling, see the [Error handling](/errors) guide.
***
## AI-powered docs
Connect our documentation to your AI coding tools via MCP so your assistant can search the Breet API docs while you build.
Install in Cursor
Install in VS Code
Copy MCP URL
The Cursor and VS Code buttons open the app directly if installed. For other tools or manual setup, copy the MCP server URL: `https://docs.breet.io/mcp`
***
## Further reading
* [Supported assets](/supported-assets): See which cryptocurrencies and stablecoins are available for deposits and withdrawals.
* [Auto-settlement](/auto-settlement): Automatically convert crypto deposits to local currency and pay out to a bank account.
* [Webhooks](/webhooks): Receive real-time notifications for crypto transactions and withdrawal events.
* [Pagination](/pagination): Navigate large result sets with page-based pagination.
* [Error handling](/errors): Understand the standard response format and common error scenarios.
* [Rate limiting](/rate-limiting): Understand API rate limits and how to handle them.
* [Use cases](/use-cases/fintech): See real integration examples for fintech, e-commerce, payroll, and more.
* [API status](https://status.breet.io/): Check real-time uptime and incident history.
# Swap Fiat Currency
Source: https://docs.breet.io/api-reference/payments/swap-fiat-currency
/api-reference/openapi.json post /payments/swap-currency
Swap fiat balance between NGN and GHS in either direction. The `from` and `to` currencies must be different.
# Crypto Prices
Source: https://docs.breet.io/api-reference/rates-and-prices/crypto-prices
/api-reference/openapi.json get /trades/pbc/sell/assets/market/converter
Returns the current global market price for a crypto-to-fiat pair. These are global market prices, not Breet-specific rates. To get Breet's actual conversion rate for NGN or GHS, use the Rate Calculator endpoint instead.
# Rate Calculator
Source: https://docs.breet.io/api-reference/rates-and-prices/rate-calculator
/api-reference/openapi.json post /trades/pbc/sell/rate-calculator/{assetId}
Calculate crypto amount and get NGN/GHS rate. This endpoint returns Breet's actual conversion rate for NGN or GHS. Use this endpoint to determine the exact amount you'll receive when converting crypto to NGN or GHS.
# Mock a trade (non-production only)
Source: https://docs.breet.io/api-reference/testing/mock-a-trade-non-production-only
/api-reference/openapi.json post /trades/sell/mock-trade
Simulates an incoming deposit so you can test your integration without sending real crypto. **Only available when `X-Breet-Env` is `sandbox`.** The wallet is identified by `walletAddress`; it must match the given asset. The trade is processed as if it came from the blockchain and will trigger the same webhooks and flows as a real deposit.
# Fetch Transaction By ID
Source: https://docs.breet.io/api-reference/transactions/fetch-transaction-by-id
/api-reference/openapi.json get /trades/transactions/{id}
Retrieve a crypto transaction using its unique id.
# Fetch Transactions
Source: https://docs.breet.io/api-reference/transactions/fetch-transactions
/api-reference/openapi.json get /trades/transactions
Retrieve all crypto transactions.
# Get a single webhook event
Source: https://docs.breet.io/api-reference/webhooks/get-a-single-webhook-event
/api-reference/openapi.json get /transactions/webhooks/{id}
Returns a stored webhook event by its `_id`. Webhooks are persisted for a fixed retention period of 7days.
# List outgoing webhook events
Source: https://docs.breet.io/api-reference/webhooks/list-outgoing-webhook-events
/api-reference/openapi.json get /transactions/webhooks
Returns paginated records of outgoing webhooks sent to your webhook URL. Webhooks are persisted for a fixed retention period of 7days.
# Resend all webhooks for a reference
Source: https://docs.breet.io/api-reference/webhooks/resend-all-webhooks-for-a-reference
/api-reference/openapi.json post /transactions/webhooks/resend/{reference}
Triggers an immediate redelivery attempt for **every** stored webhook event that matches the given `reference` (the trade or withdrawal reference). Webhooks are persisted for a fixed retention period of 7days.
# Add withdrawal address
Source: https://docs.breet.io/api-reference/withdrawal-addresses/add-withdrawal-address
/api-reference/openapi.json post /payments/wallet-addresses
Add a withdrawal (payout) wallet address for stable coins. If the same address, network, and token are sent with a different label, the existing address is updated instead of creating a duplicate. Maximum 3 addresses per user.
# Fetch withdrawal addresses
Source: https://docs.breet.io/api-reference/withdrawal-addresses/fetch-withdrawal-addresses
/api-reference/openapi.json get /payments/wallet-addresses
Fetch all saved withdrawal (payout) wallet addresses for the authenticated user or integration.
# Remove withdrawal address
Source: https://docs.breet.io/api-reference/withdrawal-addresses/remove-withdrawal-address
/api-reference/openapi.json delete /payments/wallet-addresses/{id}
Remove a saved withdrawal (payout) wallet address by ID. If the same address, network, and token is re-added later with a different label, it will be stored as a new entry (add endpoint updates the existing one only when it already exists).
# Fetch Withdrawal By ID
Source: https://docs.breet.io/api-reference/withdrawals/fetch-withdrawal-by-id
/api-reference/openapi.json get /payments/withdrawal/{id}
Retrieve a withdrawal by its ID or external ID
# Fetch Withdrawals
Source: https://docs.breet.io/api-reference/withdrawals/fetch-withdrawals
/api-reference/openapi.json get /payments/withdrawals
Retrieve all withdrawals
# Withdraw (Stable Coins)
Source: https://docs.breet.io/api-reference/withdrawals/withdraw-stable-coins
/api-reference/openapi.json post /payments/withdraw/address
Initiate withdrawal to an external stable coin wallet address
# Withdrawal (NGN | GHS)
Source: https://docs.breet.io/api-reference/withdrawals/withdrawal-ngn-|-ghs
/api-reference/openapi.json post /payments/withdraw/bank/{id}
Initiate fiat (NGN | GHS) payout to bank
# Auto-settlement
Source: https://docs.breet.io/auto-settlement
Automatically convert incoming crypto deposits to local currency and pay out to a linked bank account using the Breet API.
Breet offers two levels of auto-settlement. Both automate the process of moving funds after a crypto deposit, but they work differently and can be used independently or together.
## Per-address auto-settlement (via API)
This applies to **individual wallet addresses**. When you generate a crypto wallet address through the API, you can enable auto-settlement on that specific address. Once enabled, every deposit to that address is automatically converted and paid out to the bank account linked to it.
Without per-address auto-settlement, crypto deposits are received, converted, and held in your chosen wallet currency (USD, NGN, or GHS). You can view the balance on your dashboard. You can set your preferred currency from the dashboard under **Settings > Crypto Settings**. You must then manually initiate a withdrawal.
With per-address auto-settlement enabled, the entire flow from crypto receipt through currency conversion to bank payout happens automatically for that address.
## Business-wide auto-settlement (via dashboard)
This applies to **your entire business**. You can activate it from your dashboard under **Settings > Automatic Settlement**. Once turned on, after every transaction across all your wallet addresses, a withdrawal is automatically placed for you to a single destination of your choice.
The destination should be a bank account (NGN or GHS). This means all deposits to all addresses funnel to one place, regardless of which address received the crypto.
**Per-address** auto-settlement lets you route each wallet address to a different bank account. **Business-wide** auto-settlement sends everything to one destination. You can use either or both depending on your needs.
***
## How per-address auto-settlement works
A customer sends crypto (e.g. BTC, USDT) to a wallet address generated via your integration.
Breet detects and confirms the transaction on-chain.
The crypto is converted to USD at the current market rate and the sell is marked as completed.
If the wallet has auto-settlement enabled and a linked bank account:
* The USD amount is converted to local currency (NGN or GHS) using the current `rate`.
* If your integration has a `markupPercent` configured, the markup is deducted from the converted amount.
* The remaining amount (`amountSettled`) is sent to the linked bank account.
A webhook is sent to your configured URL with the full transaction details, including the auto-settlement fields.
***
## Prerequisites
Before per-address auto-settlement can work, complete these steps in order:
Pass bank details during address generation to automatically link the bank to the wallet.
```bash theme={null}
curl -X POST https://api.breet.io/v1/trades/sell/assets/{id}/generate-address \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"label": "my-btc-wallet",
"bankId": "BANK_ID",
"accountNumber": "0123456789",
"narration": "BTC revenue"
}'
```
If you need to change the linked bank account later, use [`PUT /trades/wallets/{id}/bank`](/api-reference/crypto-wallet/update-bank-for-existing-wallet-address).
```bash theme={null}
curl -X PUT https://api.breet.io/v1/trades/wallets/{id}/auto-settlement \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"autoSettlement": true
}'
```
The wallet **must** already have a linked bank account, otherwise the request will fail with a [`422 Unprocessable Entity`](/errors).
You can optionally set a markup percentage (0-10%) which is deducted from each settlement as your revenue margin. This can be configured via the API or from your dashboard under **Settings**.
```bash theme={null}
curl -X PUT https://api.breet.io/v1/users/markup-percent \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"markupPercent": 2.5
}'
```
You can also choose who absorbs the flat withdrawal fee on each settlement payout. Read the fee that applies to your integration from [`GET /users/fetch-integration`](/api-reference/account/fetch-account-details) as `withdrawalFee`. By default it is deducted from the payout, so the destination account is credited the settled amount minus the fee. Switch `withdrawalFeeBearer` to `business` from the **Business** tab on the **Developer** page in your [dashboard](https://partners.breet.io) to absorb it yourself and have the account credited in full — see [Who bears the fee on bank withdrawals](/withdrawals#who-bears-the-fee-on-bank-withdrawals).
The withdrawal fee and the markup are separate. The markup is deducted from the converted local-currency amount to produce `amountSettled`; the withdrawal fee is applied when that amount is paid out to the bank.
***
## Comparison
| | Per-address (API) | Business-wide (Dashboard) |
| -------------------- | ----------------------------------- | --------------------------------------------- |
| **Scope** | Individual wallet address | All wallet addresses |
| **Setup** | Enable via API per address | Toggle in **Settings > Automatic Settlement** |
| **Destination** | Bank account linked to that address | One destination for your entire business |
| **Destination type** | Bank account (NGN or GHS) | Bank account (NGN or GHS) |
| Scenario | What happens |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Both off** | Crypto is received and converted to your chosen wallet currency (USD, NGN, or GHS). Funds remain in your wallet balance. You withdraw manually from the dashboard when ready. |
| **Per-address on** | Deposits to that address are automatically converted and paid out to its linked bank account. Webhook includes settlement fields. |
| **Business-wide on** | After every transaction across all addresses, a withdrawal is automatically placed to your configured destination. |
***
## Settlement calculation
Given a crypto deposit that converts to **100 USD**, with a `rate` of **1600** (NGN per USD), and a `markupPercent` of **2.5%**:
```text theme={null}
Converted amount = 100 USD x 1600 = NGN 160,000
Markup amount = NGN 160,000 x 2.5% = NGN 4,000
Amount settled = NGN 160,000 - 4,000 = NGN 156,000
```
For Ghanaian integrations, an additional conversion from NGN to GHS is applied using the `conversionRate`.
***
## Webhook payload with auto-settlement
When a trade completes and auto-settlement is applied, the webhook payload includes these additional fields:
| Field | Type | Description |
| --------------- | ------ | -------------------------------------------------------------------------------- |
| `markupPercent` | number | The percentage markup configured on your integration (e.g. `2.5`). |
| `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. |
Auto-settlement works with or without a markup configured. When a markup percentage is set, these fields are populated with the calculated values. When no markup is set, the full converted amount is settled and these fields default to `0`.
### Example webhook (auto-settlement enabled)
```json theme={null}
{
"id": "664363cb9cfe2c4286ccf472",
"asset": "BTC",
"feePercentage": 0,
"feeAmountInUsd": 0,
"cryptoAmount": 0.0025,
"amountInUSD": 100,
"flagFeeUSD": 0,
"senderAddress": "Tvg...",
"destinationAddress": "bc1q...",
"txHash": "abc123...",
"status": "completed",
"event": "trade.completed",
"amountSettled": 156000,
"markupPercent": 2.5,
"markupAmount": 4000,
"createdAt": "2026-03-06T12:00:00.000Z",
"updatedAt": "2026-03-06T12:00:05.000Z"
}
```
For full webhook documentation including all event types and verification, see the [Webhooks](/webhooks) guide.
***
## Summary
* **Per-address auto-settlement:** Link a bank to a wallet address, enable auto-settlement on it, and every deposit to that address is automatically converted and paid out to the linked bank account. You can optionally set a markup percentage as your revenue margin.
* **Business-wide auto-settlement:** Toggle it on from the dashboard, set a single destination, and all deposits across all addresses are automatically settled there.
* **No auto-settlement:** Crypto deposits are received, converted, and held in your chosen wallet currency (USD, NGN, or GHS). You withdraw manually when ready.
Use either or both options depending on your needs.
# Deposits
Source: https://docs.breet.io/deposits
A detailed explanation concerning what happens end-to-end when crypto lands on a Breet-generated wallet address.
A **deposit** happens when crypto is sent to a wallet address you generated via the API. Breet detects the transaction on-chain, waits for confirmations, runs checks, converts the value to FIAT, and credits your Breet wallet — or pays it out to a bank if you've enabled [auto-settlement](/auto-settlement).
Every deposit, successful or not, fires a [webhook](/webhooks) so you can react in real time.
You don't need real crypto to integrate. In the `sandbox` environment, you can mock deposits to any of your addresses and exercise the full lifecycle — webhooks, confirmations, auto-settlement, everything — without sending real funds. See [Testing](/testing) for the step-by-step.
Let's dig in further.
## Deposit states
| State | What it means |
| ----------- | ---------------------------------------------------------------------------------------------- |
| `pending` | Detected on-chain, waiting for confirmations. Nothing has been credited. |
| `completed` | Fully confirmed, checks passed, wallet credited (and settled if auto-settlement is on). |
| `flagged` | Confirmed on-chain but below the asset's minimum deposit amount. Funds are held, not credited. |
Each state change fires `trade.pending`, `trade.completed`, or `trade.flagged`.
## Happy path
Call [`POST /trades/sell/assets/{id}/generate-address`](/api-reference/crypto-wallet/generate-wallet-address) once per asset per user. Addresses are permanent and reusable — no need to generate a fresh one per deposit.
Any wallet or exchange, any amount. Breet has no control over this step.
When the transaction appears on-chain, Breet creates a deposit record and fires `trade.pending` with `confirmations: 0`, the `txHash`, and the amount.
Confirmations required are configured per asset — don't hardcode them. Treat `trade.completed` or `trade.flagged` as your source of truth. `trade.pending` may fire multiple times as `confirmations` increments.
On the final confirmation, Breet checks that the deposit's USD value meets the asset's minimum ([see thresholds](/supported-assets) or call [`GET /trades/assets`](/api-reference/assets/fetch-deposit-assets)).
Meets the minimum → `completed`. Below the minimum → `flagged`.
On `completed`, Breet converts the USD value to your receive currency (USD, NGN, or GHS), deducts the platform fee (`feeAmountInUsd`), and credits your balance. `trade.completed` fires with the final amounts.
If auto-settlement is enabled on the address, Breet also pays the net amount to the linked bank account. See [Auto-settlement](/auto-settlement) for the explanation.
## Webhook sequence, by scenario
| Scenario | Events (same `id`) |
| ------------------------ | ---------------------------------------------------------------------- |
| Clean deposit | `trade.pending` → `trade.completed` |
| Slow confirmations | `trade.pending` (×N as `confirmations` increments) → `trade.completed` |
| Below minimum | `trade.pending` → `trade.flagged` |
| Flagged → later resolved | `trade.flagged` → `trade.completed` |
Use `id` + `event` as your idempotency key. Breet retries non-2xx deliveries up to 7 times — see [Webhooks](/webhooks#webhook-retries).
## What happens when a deposit is flagged
A flagged deposit is held, not lost. Example: your customer sends \$3 of USDT on Tron, minimum is \$10. The deposit sits in `flagged` until one of three things happens:
1. **Customer tops up.** Any later deposit to the **same address** in the **same asset** combines with outstanding flagged deposits at that address. The moment the combined USD total crosses the minimum, every flagged deposit flips to `completed` in one batch — one credit, one `trade.completed` per deposit. No fee applied.
2. **You pay a resolution fee from your dashboard.** Log in to [partners.breet.io](https://partners.breet.io), open the flagged transaction, click **Pay Resolution Fee**, and confirm. Breet deducts the resolution fee from the USD value of the crypto that was actually received, credits the remainder to your wallet immediately, and fires `trade.completed` with the `flagFeeUSD` field populated so your system knows a fee was applied.
3. **You've turned on auto-resolution.** When trade auto-resolution is enabled on your integration, Breet handles step 2 automatically the moment a deposit is flagged — it deducts the resolution fee from the USD value of the crypto that was actually received, credits the remainder to your wallet, and fires `trade.completed` with `flagFeeUSD` populated. No dashboard action, no waiting on the customer. Turn this on from the **Business** tab on the **Developer** page in your [dashboard](https://partners.breet.io).
## Edge cases
### Wrong asset
If a customer sends a **different asset** to one of your addresses (e.g. they send ETH to a USDT address), recovery is **automatic** — no support ticket needed. This applies only if the received asset is one of our [supported assets](/supported-assets).
What happens behind the scenes:
1. We detect the asset mismatch.
2. A new address is generated on your integration for the asset that actually arrived. The original wallet's bank account and auto-settlement configurations are carried over.
3. The deposit processes as a normal trade on the new wallet.
**Webhooks you'll receive, in order:**
* [`trade.address.created`](https://docs.breet.io/webhooks#address-creation-webhook) — new address payload with `id`, `address`, `asset`, `label`, and `createdAt`.
* An email from us confirming the mismatch and recovery. No action needed on your end.
* `trade.pending` → `trade.completed` — standard trade lifecycle on the new wallet. The `trade.pending` payload includes `isWrongAssetDeposit: true` so you can identify this as a wrong-asset recovery.
* If auto-settlement was **on**: `withdrawal.pending` → `withdrawal.processing` → `withdrawal.completed`. Funds settle to the bank account from the original wallet.
* If auto-settlement was **off**: funds credit your dashboard balance. Resolve with your user from there as you normally would.
### USD value and timing
`amountInUSD` is recalculated on each webhook, not locked at detection. The value on `trade.completed` is authoritative — use it for accounting. Local-currency conversion uses the `rate` at completion time.
### Chain reorganisations
Rare on supported networks. If a pending deposit is orphaned before it confirms, the deposit moves to a non-credited terminal state — always before `trade.completed` could fire.
## Fetching deposits via the API
Rather than relying only on webhooks, you can inspect deposits directly:
| Purpose | Endpoint |
| -------------------------- | -------------------------------------------------------------------------------------- |
| List deposits | [`GET /trades/transactions`](/api-reference/transactions/fetch-transactions) |
| Fetch one by ID | [`GET /trades/transactions/{id}`](/api-reference/transactions/fetch-transaction-by-id) |
| List your wallet addresses | [`GET /trades/wallets`](/api-reference/crypto-wallet/fetch-wallet-addresses) |
On every webhook, fetch the deposit by `id` before updating your system of record. Combined with [IP and secret verification](/webhooks#webhook-verification), this is defence in depth.
## FAQ
Seconds/Minutes on Solana/Tron/TON; up to an hour on slow chains. If a deposit is pending for more than 6 hours, contact support with the `txHash`.
No. Generate a separate address per customer (or per order) and pass their ID in the `label` field. When a deposit webhook fires, `destinationAddress` and `destinationDescription` (the label) tell you exactly who paid.
Addresses are permanent and reusable, so you generate a customer's address once, store it, and reuse it for all their future deposits.
No. Your customer pays their own on-chain fee. Breet's only charge on a deposit is the platform fee (`feeAmountInUsd`).
`feeAmountInUsd` is the platform fee on a normal completed deposit. `flagFeeUSD` is the resolution fee applied when you pay to release a flagged below-minimum deposit from your dashboard. On the happy path, `flagFeeUSD` is `0`.
## Next steps
* Move funds out of your wallet → [Withdrawals](/withdrawals)
* Set up webhook handling → [Webhooks](/webhooks)
* Settle deposits automatically → [Auto-settlement](/auto-settlement)
* See supported assets and minimums → [Supported assets](/supported-assets)
* Simulate a deposit on testnet → [Testing](/testing)
# Error handling
Source: https://docs.breet.io/errors
Understand Breet API error responses, HTTP status codes, and how to handle common error scenarios in your integration.
## Response format
### Success responses
Successful requests return a JSON object with the following shape:
```json theme={null}
{
"success": true,
"message": "wallets retrieved successfully",
"data": { ... },
"meta": { ... }
}
```
| Field | Type | Description |
| --------- | --------------- | -------------------------------------------------------------------------------- |
| `success` | boolean | Always `true` for successful requests. |
| `message` | string | A human-readable description of the result. |
| `data` | object or array | The response payload. May be an object, an array, or empty `{}`. |
| `meta` | object | Metadata such as [pagination](/pagination) info. Empty `{}` when not applicable. |
### Error responses
Failed requests return a JSON object with the following shape:
```json theme={null}
{
"success": false,
"message": "TRX_TEST for your-wallet-label already exists in your wallets",
"meta": {},
"errors": [],
"data": {}
}
```
| Field | Type | Description |
| --------- | ------- | ------------------------------------------------ |
| `success` | boolean | Always `false` for failed requests. |
| `message` | string | A human-readable description of what went wrong. |
| `errors` | array | Additional error details when available. |
| `meta` | object | Empty for error responses. |
| `data` | object | Empty for error responses. |
Not all error responses include every field. See the exceptions for **429** and **500** below.
## Common error scenarios
### 400 - Bad request
Returned when the request is invalid or violates a business rule.
**Duplicate wallet label:**
```json theme={null}
{
"success": false,
"message": "TRX_TEST for your-wallet-label already exists in your wallets",
"meta": {},
"errors": [],
"data": {}
}
```
This occurs when you attempt to generate a wallet address with a label that already exists for the same asset.
### 401 - Unauthorized
Returned when authentication credentials are missing or invalid. Ensure you are sending the correct `x-app-id` and `x-app-secret` headers, and that the `X-Breet-Env` header is set to either `sandbox` or `production`. See the [quickstart](/quickstart) for how to obtain and configure your credentials.
### 403 - Forbidden
Returned when your account does not have permission to perform the requested action.
```json theme={null}
{
"success": false,
"message": "access is forbidden",
"meta": {},
"errors": [],
"data": {}
}
```
### 404 - Not found
Returned when the requested resource does not exist.
**Wallet not found:**
```json theme={null}
{
"success": false,
"message": "wallet not found",
"meta": {},
"errors": [],
"data": {}
}
```
**Transaction not found:**
```json theme={null}
{
"success": false,
"message": "transaction not found",
"meta": {},
"errors": [],
"data": {}
}
```
### 409 - Conflict
Returned when the request conflicts with the current state of a resource, such as attempting to create a resource that already exists.
### 422 - Unprocessable entity
Returned when the request is well-formed but cannot be processed due to a validation or business logic constraint.
```json theme={null}
{
"success": false,
"message": "wallet does not have a bank",
"meta": {},
"errors": [],
"data": {}
}
```
This commonly occurs when enabling [auto-settlement](/auto-settlement) on a wallet that doesn't have a linked bank account.
### 429 - Too many requests
Returned when you exceed the [rate limit](/rate-limiting). Back off and retry after the time indicated in the `Retry-After` response header (value in seconds).
The 429 response body does **not** follow the standard error shape. It only returns a `message` field:
```json theme={null}
{
"message": "Too many requests. Please try again later."
}
```
Your error handling should account for this exception.
### 500 - Internal server error
Returned when an unexpected error occurs on the server. The response body includes `success`, `message`, `meta`, and `errors`, but does **not** include a `data` field:
```json theme={null}
{
"success": false,
"message": "something went wrong!",
"meta": {},
"errors": []
}
```
For 500 errors, implement retry logic with exponential backoff.
## Best practices
* Always check the `success` field before processing the response.
* Use the `message` field for logging and debugging. Do not rely on exact message text for control flow, as messages may change.
* Handle `4xx` errors gracefully in your application with appropriate user feedback.
* For `429` errors, read the `Retry-After` header to determine how long to wait before retrying.
* For `5xx` errors, implement retry logic with exponential backoff.
# FAQs
Source: https://docs.breet.io/faqs
Answers to frequently asked questions about the Breet API, pricing, supported countries, integration, and more.
## Integration
Integration is usually very straightforward. In some cases, it can be done in a few hours, and for others it may take a few days depending on your current setup and how quickly your developers move. Our team is also available to support you through the process, so if you need guidance at any point, we are there to help make it smoother.
Our API gives businesses a simpler way to add crypto and stablecoin rails to their product without having to build the infrastructure themselves. We handle the complexity behind the scenes, so you can offer your users another way to move value through your product without distracting your team with the technical and operational work behind crypto.
Through our API, you can:
* Generate permanent crypto wallet addresses for your users
* Implement crypto deposits in your application
* Automate crypto to fiat conversion
* Automate crypto settlements into local bank accounts
* Support stablecoin withdrawals
**What makes Breet different?** With Breet, you do not need to worry about managing crypto infrastructure, running gas stations, handling node operations, or dealing with any of the complicated backend work that comes with supporting crypto. We abstract all of that away so your team can focus on building your product. On top of that, our pricing is straightforward and competitive, with no monthly platform fees, no limits on wallet addresses, and no hidden costs that grow as you scale.
To get started, you will need to provide the following:
* Recent proof of address
* Evidence of registration or incorporation
* Memorandum and articles of association
* Status report
* Directors KYC
* Business email
## Transactions and settlements
For fiat payouts to bank accounts, settlement is instant. For incoming crypto transactions, timing depends on the blockchain and asset involved, since different networks move at different speeds and require different confirmations. That said, our system is built to handle the process as smoothly and as quickly as possible.
Our rates are market-driven, based on current demand and supply at the time of the transaction. You can be confident that our rates are highly competitive, and we always go out of our way to provide you with the best available rate. Rates can be viewed on the dashboard or fetched programmatically using the [Rate Calculator](/api-reference/rates-and-prices/rate-calculator) endpoint.
The way the Breet API is designed, partners do not need to deal with the complexity of holding crypto. Instead, value is converted and settled into USD, Naira, or Cedis. If your use case also requires sending out crypto, that is supported. You can keep your balance in USD and withdraw in stablecoins.
There is no fixed maximum amount. Any value that is sent will be settled appropriately. For minimum amounts, that depends on the crypto asset involved, and those thresholds are documented on the [Supported Assets](/supported-assets) page.
Yes, unique wallet addresses can be created per user. In fact, that is the expected setup. Once an address is generated for a user, it is stored on your end and reused for future transactions.
If a user sends the wrong asset to one of your generated addresses (e.g. they send ETH to a USDT address), we handle recovery automatically — no support ticket needed on your end. This applies only if the asset received is one of our [supported assets](/supported-assets).
Here's what happens:
1. We detect that the received asset doesn't match the address it was sent to.
2. We generate a new address on your integration for the asset that actually arrived, carrying over the original wallet's bank account and auto-settlement settings.
3. The deposit is processed as a normal trade on the new wallet.
You'll receive a [`trade.address.created`](https://docs.breet.io/webhooks#address-creation-webhook) webhook for the new address, followed by the standard `trade.pending` → `trade.completed` lifecycle. If auto-settlement was enabled on the original wallet, a withdrawal will follow automatically. If it was off, funds credit your dashboard balance for you to resolve with your user.
That said, it's still best practice to make the correct asset and network clear in your flow before a user initiates a transfer.
Yes, we support OTC trades for large volumes. We have a dedicated OTC desk for transactions like that, so if your use case involves higher-volume trades, there is already a proper channel to handle it. Where needed, we can connect you directly to the OTC desk.
## Pricing
Transaction fees are based on your volume, with pricing that adjusts as your transaction volume grows. There are no setup fees, no monthly fees, and no hidden spreads. Where applicable, network or withdrawal fees may apply. Overall, it's a straightforward, transparent pay-as-you-go model.
## Coverage and support
We support partners in many countries where the use case is built around crypto or stablecoin flows. However, for fiat settlement into local bank accounts, we currently support **Nigeria** and **Ghana**. So if your use case is around crypto or stablecoin movement, there is more flexibility, while direct fiat settlement is limited to those two markets for now.
We provide direct support to partners during integration and beyond, so you are not left to figure things out on your own. We usually set up a dedicated support channel on either Slack or WhatsApp, depending on your preference, so there is always a direct line for questions, guidance, and issue resolution.
Yes, we offer SLAs. If you need specific uptime or response-time commitments, that is something we can discuss based on your use case and plan.
## Reliability and security
Failed transactions are handled properly and do not just disappear into the system. If an outgoing crypto or fiat transaction fails, it is reversed automatically, so the value is not left hanging without a clear outcome.
If your system goes down mid-transaction, the flow is not abandoned. We have a retry process in place for webhook delivery, so if your system is temporarily unavailable, we keep attempting delivery within the [retry window](/webhooks#webhook-retries). The goal is to make sure important transaction updates are not missed because of temporary downtime.
Yes, you can whitelist IPs and restrict API access. In fact, we encourage it, because it adds another layer of control and helps ensure requests are only coming from trusted sources on your end.
## Data and reporting
Yes, transaction history is available so partners can track activity across their flow. Since transaction updates are also sent through webhooks, partners can maintain and structure records on their end as well. If there is a specific reporting format you need, that is something we can discuss based on your use case.
Yes, reconciliation can be automated because transaction data is available through the API and webhook updates are sent as events happen. This allows partners to build their flow in a way that supports easier matching and reconciliation on their side.
Webhooks are available for the major transaction events that partners need to track. This includes incoming transaction updates (pending, completed, or flagged) and withdrawal updates (pending, completed, reversed, or rejected). For full details, see the [Webhooks](/webhooks) guide.
# API Introduction
Source: https://docs.breet.io/index
Integrate crypto payments into your product with the Breet API. Accept deposits, convert assets, and settle to bank accounts in local currency.
## Built with simplicity in mind
Breet's crypto API infrastructure is **simple on purpose**.
Most businesses just want to accept crypto or stablecoin payments without worrying about networks, confirmations, fees, or compliance. That's exactly what we built for.
Instead of packing in features you'll never use, we focused on what actually matters: receiving crypto, converting it, and settling to bank accounts. Nothing more, nothing less.
The result is an API that **works quietly** in the background, does exactly what it promises, and never gets in the way of your product.
## Get started
Get your API credentials and make your first request in minutes.
Authentication, base URL, and full endpoint documentation.
Try the API Demo to explore and test the API flows in an interactive environment.
## Who can build with Breet API?
Let users fund accounts with crypto and settle in local currency.
Accept crypto deposits and pay out winnings to bank accounts.
Add crypto checkout and auto-settle to your local currency.
Use Breet as settlement infrastructure for trades.
Accept crypto payments for subscriptions and digital products.
Pay remote employees in Africa via stablecoin-to-bank payouts.
Convert crypto to local currency and settle to bank accounts.
Buy stablecoins with your USD balance and send to any wallet.
## Need help?
* **Partner support group:** Every onboarded API partner gets a dedicated support group (Whatsapp / Slack). If you're already integrated, reach out to your team there for the fastest response.
* **Not onboarded yet?** [Book a demo](https://breet.io/business/book-a-call) to get started and get access to your dedicated support group.
* **API status:** Check real-time uptime and incident history at [status.breet.io](https://status.breet.io/).
* **Support Email:** [support@breet.io](mailto:support@breet.io)
# Pagination
Source: https://docs.breet.io/pagination
Learn how to paginate through large result sets in the Breet API using page and size query parameters. Includes supported endpoints and response examples.
Endpoints that return lists of resources support pagination through query parameters. This allows you to retrieve data in manageable chunks rather than loading everything at once.
## Query parameters
| Parameter | Type | Default | Description |
| --------- | ------- | ------- | ------------------------- |
| `page` | integer | `1` | Page number (1-indexed). |
| `size` | integer | `10` | Number of items per page. |
### Example request
```bash theme={null}
curl -X GET "https://api.breet.io/v1/trades/wallets?page=1&size=10" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production"
```
## Paginated response
Every paginated endpoint returns a `meta` object alongside the `data` array. The `meta` object contains all the information you need to navigate through result pages:
```json theme={null}
{
"success": true,
"message": "wallets retrieved successfully",
"data": [ ... ],
"meta": {
"pages": 2,
"prevPage": null,
"nextPage": 2,
"page": 1,
"totalDocs": 12,
"hasPrevPage": false,
"hasNextPage": true
}
}
```
### Meta fields
| Field | Type | Description |
| ------------- | --------------- | ----------------------------------------------------- |
| `pages` | integer | Total number of pages available. |
| `prevPage` | integer or null | Previous page number, or `null` if on the first page. |
| `nextPage` | integer or null | Next page number, or `null` if on the last page. |
| `page` | integer | Current page number. |
| `totalDocs` | integer | Total number of documents across all pages. |
| `hasPrevPage` | boolean | Whether a previous page exists. |
| `hasNextPage` | boolean | Whether a next page exists. |
## Supported endpoints
The following endpoints support pagination:
| Endpoint | Method | Description |
| ------------------------------------------------------------------------ | ------ | ------------------------- |
| [`/trades/wallets`](/api-reference/crypto-wallet/fetch-wallet-addresses) | GET | Fetch wallet addresses |
| [`/trades/transactions`](/api-reference/transactions/fetch-transactions) | GET | Fetch transactions |
| [`/payments/integration-banks`](/api-reference/banks/fetch-saved-banks) | GET | Fetch saved bank accounts |
| [`/payments/withdrawals`](/api-reference/withdrawals/fetch-withdrawals) | GET | Fetch withdrawals |
## Iterating through pages
To retrieve all results, start at `page=1` and keep requesting the next page until `hasNextPage` is `false`:
```javascript theme={null}
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await fetch(
`https://api.breet.io/v1/trades/wallets?page=${page}&size=20`,
{ headers: { "x-app-id": APP_ID, "x-app-secret": APP_SECRET, "X-Breet-Env": "production" } }
);
const { data, meta } = await response.json();
// Process data
processWallets(data);
hasMore = meta.hasNextPage;
page = meta.nextPage;
}
```
# Quickstart
Source: https://docs.breet.io/quickstart
Get your Breet API credentials, set up authentication headers, and make your first API request in minutes.
## Prerequisites
* A [Breet Partner Account](https://partners.breet.io/register)
* Your **App ID** and **App Secret** from the dashboard
Don't have API dashboard access? Fill out this form to speak with our team and get set up.
## Step 1: Get your credentials
1. Log in to the [Breet API Dashboard](https://partners.breet.io).
2. Go to **Settings → For Developer**.
3. Create or copy your **App ID** and **App Secret (API Secret Key)**.
**Keep your App Secret safe.** Never expose it in frontend code, mobile apps, or public repositories. Store it in environment variables or a secrets manager.
## Step 2: Set required headers
Every API request must include:
| Header | Description |
| -------------- | ------------------------- |
| `x-app-id` | Your App ID |
| `x-app-secret` | Your App Secret |
| `X-Breet-Env` | `sandbox` or `production` |
## Step 3: Make your first request
**Base URL:** `https://api.breet.io/v1`
Example 1: list supported assets.
```bash theme={null}
curl -X GET "https://api.breet.io/v1/trades/assets" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: sandbox"
```
Example 2: generate a deposit wallet address (replace `ASSET_ID` with a valid asset ID from the assets list).
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: sandbox" \
-H "Content-Type: application/json" \
-d '{"label": "my-first-wallet"}'
```
## AI-powered docs
Connect our documentation to your AI coding tools via MCP so your assistant can search the Breet API docs while you build.
Install in Cursor
Install in VS Code
Copy MCP URL
The Cursor and VS Code buttons open the app directly if installed. For other tools or manual setup, copy the MCP server URL: `https://docs.breet.io/mcp`
## Next steps
* Read the [API overview](/api-reference/introduction) for full authentication and security details.
* Explore the [API reference](/api-reference/introduction) for all endpoints, request bodies, and responses.
* Enable [auto-settlement](/auto-settlement) to automatically convert crypto deposits to local currency and pay out to a bank account.
* Set up [webhooks](/webhooks) to receive real-time events when funds arrive or withdrawals complete.
* Learn about [pagination](/pagination), [error handling](/errors), and [rate limiting](/rate-limiting).
* Browse [use cases](/use-cases/fintech) to see how teams integrate Breet for fintech, e-commerce, payroll, and more.
* Try the **[API Demo](https://apidemo.breet.io)** to explore and test the API flows in an interactive environment.
# Rate limiting
Source: https://docs.breet.io/rate-limiting
Understand Breet API rate limits, retry headers, and best practices for handling 429 responses.
Breet enforces rate limits to ensure platform stability and fair usage across all integrations.
## Limits
| Endpoint | Limit |
| ----------------------------------------------------------------------------------------------- | ----------------------- |
| [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) | 200 requests per minute |
| [`POST /payments/wallet-addresses`](/api-reference/withdrawal-addresses/add-withdrawal-address) | 5 requests per minute |
| All other endpoints | 500 requests per minute |
Rate limits are applied **per integration and per route**. This means hitting the withdrawal endpoint does not affect your rate limit on the withdrawal-addresses endpoint, and vice versa. Limits are tracked using the authentication credentials (`x-app-id`) in your request headers. Route-specific limits replace the default 500 for that route only.
## Response headers
Rate-limited endpoints include the following headers in every response:
| Header | Description |
| ----------------------- | ------------------------------------------------------------------------------------------ |
| `X-RateLimit-Limit` | Maximum number of requests allowed per window (e.g., `200`). |
| `X-RateLimit-Remaining` | Number of requests remaining in the current window. |
| `X-RateLimit-Reset` | Unix timestamp (in seconds) when the rate limit window resets. Included on every response. |
| `Retry-After` | Number of seconds to wait before retrying. Only included on `429` responses. |
### Example response headers
```
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 199
X-RateLimit-Reset: 1769099817
```
## Handling rate limits
When you exceed the rate limit, the API returns a **429 Too Many Requests** status code. See [error handling](/errors) for the full 429 response format. To handle this gracefully:
1. Check the `X-RateLimit-Remaining` header before making requests. If it is approaching `0`, slow down.
2. If you receive a `429` response, use the `Retry-After` header (value in seconds) to determine how long to wait before retrying.
3. Add a retry loop so transient rate limit hits don't break your integration.
### Example retry logic
```javascript theme={null}
async function withdrawWithRetry(payload, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch("https://api.breet.io/v1/payments/withdraw/address", {
method: "POST",
headers: {
"x-app-id": APP_ID,
"x-app-secret": APP_SECRET,
"X-Breet-Env": "production",
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (response.status !== 429) return response.json();
const retryAfter = response.headers.get("Retry-After");
const waitMs = Number(retryAfter) * 1000;
await new Promise((resolve) => setTimeout(resolve, Math.max(waitMs, 1000)));
}
throw new Error("Rate limit exceeded after retries");
}
```
## Best practices
* **Batch operations** where possible to reduce the total number of API calls.
* **Monitor headers** proactively. Don't wait for a `429` to start throttling.
* **Queue withdrawals** on your end and process them at a steady rate below the limit.
# Supported assets
Source: https://docs.breet.io/supported-assets
Cryptocurrencies and stablecoins supported for deposits and withdrawals on the Breet API, including networks, tokens, and minimum amounts.
The assets listed on this page are a snapshot and may not reflect real-time availability. Assets can be added, removed, or temporarily disabled at any time. Always call the [`GET /trades/assets`](/api-reference/assets/fetch-deposit-assets) endpoint to get the current list of active assets for your integration. Each asset includes an `isActive` flag indicating whether it is currently available.
## Deposit assets (mainnet)
These are the mainnet cryptocurrencies and stablecoins your users can send to Breet-generated wallet addresses. Use these asset IDs in the `production` environment.
### Native coins
| Asset | Network | Asset ID | Min. deposit (USD) |
| ------------ | ----------------- | --------- | ------------------ |
| Bitcoin | Bitcoin | `BTC` | 2 |
| Ethereum | Ethereum | `ETH` | 5 |
| Solana | Solana | `SOL` | 5 |
| Tron | Tron | `TRX` | 5 |
| BNB | BNB Smart Chain | `BNB_BSC` | 5 |
| Avalanche | Avalanche C-Chain | `AVAX` | 5 |
| Litecoin | Litecoin | `LTC` | 2 |
| Bitcoin Cash | Bitcoin Cash | `BCH` | 2 |
| Dogecoin | Dogecoin | `DOGE` | 2 |
| TON | The Open Network | `TON` | 2 |
| XRP | Ripple | `XRP` | 2 |
### USDT (Tether)
| Network | Asset ID | Min. deposit (USD) |
| ---------------- | --------------- | ------------------ |
| Tron (TRC20) | `TRX_USDT_S2UZ` | 10 |
| Ethereum (ERC20) | `USDT_ERC20` | 10 |
| Solana | `SOL_USDT_EWAY` | 10 |
| BNB Smart Chain | `USDT_BSC` | 10 |
| Polygon | `USDT_POLYGON` | 10 |
| TON | `USDT_TON` | 10 |
### USDC (Circle)
| Network | Asset ID | Min. deposit (USD) |
| ---------------- | ------------------------- | ------------------ |
| Ethereum (ERC20) | `USDC` | 10 |
| Solana | `SOL_USDC_PTHX` | 10 |
| Arbitrum | `USDC_ARB_3SBJ` | 10 |
| Base | `USDC_BASECHAIN_ETH_5I5C` | 10 |
| Polygon | `USDC_POLYGON_NXTB` | 10 |
Deposits below the minimum amount are flagged. Breet sends a `trade.flagged` [webhook](/webhooks) when this happens. Check the minimum for each asset before displaying deposit instructions to your users.
***
## Withdrawal assets (mainnet)
Withdrawals to external crypto addresses only support **stablecoins** (USDT and USDC).
| Network | USDT | USDC |
| --------------------- | ---- | ---- |
| Ethereum (ERC20) | Yes | Yes |
| Tron (TRC20) | Yes | Yes |
| BNB Smart Chain (BSC) | Yes | Yes |
| Solana | Yes | Yes |
| TON | Yes | No |
Use the [Withdraw (Stablecoins)](/api-reference/withdrawals/withdraw-stable-coins) endpoint to send stablecoins to an external wallet address.
***
## Test assets (testnet)
In the `sandbox` environment, you can use test assets to simulate deposits and withdrawals without real funds. All test assets have a minimum deposit of **\$1 USD**.
Set the `X-Breet-Env` header to `sandbox` to use test assets. See the [quickstart](/quickstart) for environment setup.
### Base assets
| Chain | Testnet ID | Min. deposit (USD) |
| ------------ | ----------- | ------------------ |
| Bitcoin | `BTC_TEST` | 1 |
| Ethereum | `ETH_TEST5` | 1 |
| Solana | `SOL_TEST` | 1 |
| Tron | `TRX_TEST` | 1 |
| BNB | `BNB_TEST` | 1 |
| Avalanche | `AVAXTEST` | 1 |
| Litecoin | `LTC_TEST` | 1 |
| Bitcoin Cash | `BCH_TEST` | 1 |
| Dogecoin | `DOGE_TEST` | 1 |
| TON | `TON_TEST` | 1 |
| XRP | `XRP_TEST` | 1 |
### USDT (Tether)
| Network | Testnet ID | Min. deposit (USD) |
| ---------------- | ------------------------------ | ------------------ |
| Tron (TRC20) | `USDT_TRX_TEST2` | 1 |
| Ethereum (ERC20) | `USDT_ETH_TEST5_WFZR` | 1 |
| Solana | `USDT_B7ZDHS8D_TOR7` | 1 |
| BNB Smart Chain | `USDT_BSC_TEST` | 1 |
| Polygon | `USD_POLYGON_TEST_MUMBAI_QFXA` | 1 |
| TON | `USDTTT_TON_TEST` | 1 |
### USDC (Circle)
| Network | Testnet ID | Min. deposit (USD) |
| ---------------- | ------------------------------- | ------------------ |
| Ethereum (ERC20) | `USDC_ETH_TEST5_0GER` | 1 |
| Solana | `SOL_USDC_JKVK` | 1 |
| Arbitrum | `USDC_ARB_SEPOLIA_V84S` | 1 |
| Base | `USDC_BASECHAIN_ETH_TEST5_8SH8` | 1 |
| Polygon | `USDC_AMOY_POLYGON_TEST_7WWV` | 1 |
***
## Supported countries
Bank withdrawals (fiat settlements) are currently available in the following countries:
| Country | Currency | Code |
| ------- | -------------- | ---- |
| Nigeria | Nigerian Naira | NGN |
| Ghana | Ghanaian Cedi | GHS |
Use the [Withdrawal (NGN | GHS)](/api-reference/withdrawals/withdrawal-ngn-|-ghs) endpoint to settle funds to a bank account in either country.
***
## Always fetch from the API
Asset availability can change based on your integration, network conditions, or business configuration. Always call the [`GET /trades/assets`](/api-reference/assets/fetch-deposit-assets) endpoint to get the current list. Each asset in the response includes:
* `id` - the asset ID to use in API calls
* `name` - the human-readable name (e.g., "USDT (Solana)")
* `symbol` - the token symbol (e.g., "USDT")
* `isActive` - whether the asset is currently available
* `minimum` - the minimum deposit amount in USD
# Testing
Source: https://docs.breet.io/testing
Test deposits and flows in the sandbox environment using the mock trade endpoint.
## Mock trade (sandbox only)
In **sandbox** (`X-Breet-Env: sandbox`), you can simulate an incoming deposit without sending real crypto. This lets you:
* Test webhooks and notification flows end-to-end
* Verify auto-settlement and payout logic
* Exercise your app against the same trade lifecycle as production
## How it works
1. You already have at least one wallet address (from [Generate Wallet Address](/api-reference/crypto-wallet/generate-wallet-address) or [Fetch Wallet Addresses](/api-reference/crypto-wallet/fetch-wallet-addresses)).
2. You send a `POST /trades/sell/mock-trade` request with:
* **walletAddress** — the deposit address to credit
* **asset** — must match that wallet’s asset (e.g. `TRX_TEST`)
* **amountInUSD**, **cryptoReceived** — amounts for the mock deposit
* **reference**, **txHash** — unique identifiers for the mock transaction
3. The API enqueues the trade as if it had been received from the blockchain. Your webhooks and any downstream flows (e.g. auto-settlement) run as they would for a real deposit.
## Example request
Full request and response details: [Mock a trade (POST /trades/sell/mock-trade)](/api-reference/testing/mock-a-trade-non-production-only).
Minimal body (required fields only):
```json theme={null}
{
"walletAddress": "TV8dNYYBgL3xLbQcJLMBNavY4gYNqPF8Jv",
"asset": "TRX_TEST",
"amountInUSD": 50,
"cryptoReceived": 500,
"reference": "mock-ref-550e8400-e29b-41d4-a716-446655440000",
"txHash": "0xmock550e8400e29b41d4a716446655440000"
}
```
With optional fields:
```json theme={null}
{
"walletAddress": "TV8dNYYBgL3xLbQcJLMBNavY4gYNqPF8Jv",
"asset": "TRX_TEST",
"amountInUSD": 100,
"cryptoReceived": 1000,
"reference": "mock-ref-660e8400-e29b-41d4-a716-446655440001",
"txHash": "0xmock660e8400e29b41d4a716446655440001",
"sourceAddress": "TSource1234567890AbCdEfGhIjKlMnOpQr",
"confirmations": 12
}
```
## cURL example
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/mock-trade" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: sandbox" \
-H "Content-Type: application/json" \
-d '{
"walletAddress": "TV8dNYYBgL3xLbQcJLMBNavY4gYNqPF8Jv",
"asset": "TRX_TEST",
"amountInUSD": 50,
"cryptoReceived": 500,
"reference": "mock-ref-550e8400-e29b-41d4-a716-446655440000",
"txHash": "0xmock550e8400e29b41d4a716446655440000"
}'
```
## Responses
| Status | Meaning |
| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **200** | Mock trade accepted; processing runs asynchronously (same as a real deposit). |
| **403** | Mock trade is not allowed — you are in production or not using `X-Breet-Env: sandbox`. |
| **404** | No wallet found for the given `walletAddress` and `asset`. Ensure the address exists and matches the asset (e.g. from [Fetch Wallet Addresses](/api-reference/crypto-wallet/fetch-wallet-addresses)). |
| **422** | Validation error (e.g. missing required field, invalid asset). Check the response body for details. |
After a successful request, you can confirm the trade and related webhooks in your dashboard and via your webhook endpoint.
## Simulating withdrawal statuses (sandbox only)
In **sandbox** (`X-Breet-Env: sandbox`), the `amount` you submit on a withdrawal request decides the final status, so you can exercise each branch of the [withdrawal lifecycle](/withdrawals) — `reversed`, `processing`, and `completed`.
### Amount-based rules
Find the row for the currency you're withdrawing in. To trigger a `reversed` withdrawal, send any `amount` at or below the value in the first column. To make it stop at `processing`, send the exact value in the second column. Any other `amount` will go straight through to `completed`.
| Currency | `reversed` when `amount` ≤ | `processing` when `amount` = | `completed` otherwise |
| -------- | -------------------------- | ---------------------------- | --------------------- |
| NGN | `5,000` | `10,000` | any other amount |
| GHS | `10` | `100` | any other amount |
| USD | `15` | `50` | any other amount |
* **At or below the failure threshold** → `withdrawal.pending` → `withdrawal.reversed`. Use this to test refund handling.
* **Exactly the pending threshold** → `withdrawal.pending` → `withdrawal.processing`. The withdrawal stops at `processing` so you can test how your system handles a long-running processing state.
* **Any other amount** → `withdrawal.pending` → `withdrawal.completed`. Standard happy path.
These rules are scoped to sandbox only. In production, withdrawals run through the normal flow and the final status reflects the actual outcome.
# Betting & gaming
Source: https://docs.breet.io/use-cases/betting-gaming
Enable crypto deposits and bank payouts for betting and gaming platforms. Accept stablecoins and settle winnings to local accounts with Breet.
Let players fund their betting balance with crypto and withdraw winnings to their bank account or as stablecoins. Breet handles wallet generation, deposit tracking, and payout processing so your platform can focus on the gaming experience.
## How it works
Call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint with the player's internal ID as the `label`. Each address is permanent, so you only need to generate it once per player per asset. Store it and display it whenever the player initiates a deposit.
Display the wallet address in your deposit flow. The player sends crypto from any external wallet or exchange.
Breet sends a [webhook](/webhooks) when the deposit is confirmed on-chain. Parse the payload and credit the player's betting balance.
When a player requests a withdrawal, call [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to send stablecoins to their wallet, or [`POST /payments/withdraw/bank/{id}`](/api-reference/withdrawals/withdrawal-ngn-|-ghs) to settle to a bank account.
## Generate a deposit address
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{"label": "player-78901"}'
```
Replace `ASSET_ID` with the asset the player wants to deposit (e.g., USDT, BTC). The `label` field ties the address to a specific player for automatic reconciliation. Each address is **permanent**, so you only need to generate it once per player per asset.
Generate a unique address per player so deposits are automatically attributed without manual matching.
## What Breet handles
* Generating unique deposit addresses per player
* Monitoring blockchains for incoming deposits
* Sending real-time webhook notifications
* Processing stablecoin withdrawals to player wallets
* Auto-settlement to local bank accounts (NGN or GHS)
## What you handle
* Displaying deposit addresses and QR codes in your platform
* Listening for and processing webhook events
* Crediting and debiting player balances
* Managing withdrawal requests and payout logic
* Enforcing your platform's deposit and withdrawal limits
## Example user journey
1. Chidi opens a betting platform and taps **Deposit**.
2. He selects **USDT on Tron** as his deposit method.
3. If this is Chidi's first deposit, the platform calls Breet's [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint and stores the returned TRC-20 wallet address. For future deposits, the platform displays the same saved address since it is permanent.
4. Chidi sends 100 USDT from his exchange account.
5. Breet detects the deposit and sends a `trade.completed` webhook.
6. The platform credits 100 USDT to Chidi's betting balance.
7. After a winning streak, Chidi requests a withdrawal of 250 USDT.
8. The platform calls [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to send 250 USDT to Chidi's personal wallet.
9. Chidi receives the stablecoins and a `withdrawal.completed` webhook confirms the payout.
## FAQ
Yes. Use [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to send stablecoins (USDT or USDC) to any wallet address the player provides. You can also settle winnings to a bank account using [`POST /payments/withdraw/bank/{id}`](/api-reference/withdrawals/withdrawal-ngn-|-ghs).
Yes. Each call to the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint returns a new address. Use the `label` field to tag it with the player's ID so incoming deposits are automatically mapped to the correct account.
Deposits below the network's minimum threshold may be flagged. Breet sends a `trade.flagged` webhook when a deposit falls below the asset minimum. Check the [supported assets](/supported-assets) page for minimum amounts.
Breet monitors the blockchain independently of your platform's availability. If your webhook endpoint is unreachable, Breet retries delivery using an exponential backoff schedule. See [webhook retries](/webhooks#webhook-retries) for the full retry timeline.
# Crypto payouts
Source: https://docs.breet.io/use-cases/crypto-payouts
Turn your business balance into outbound crypto payments. Fund your account with crypto or Naira, then send stablecoin payouts to any wallet address worldwide.
Built for businesses moving stablecoins to customers and partners: fintechs whose users withdraw or buy stablecoins, marketplaces settling vendors, platforms paying creators and contractors, betting platforms paying winnings, and businesses paying overseas suppliers.
## How it works
Your USD balance funds your crypto payouts. There are two ways to build it up:
* **Crypto deposits.** Generate a deposit address from your dashboard, or over the API with [`POST /trades/sell/assets/{id}/generate-address`](/api-reference/crypto-wallet/generate-wallet-address).
* **Naira transfers** to the virtual account on your dashboard, converted with [`POST /payments/fiat-to-usd`](/api-reference/conversion/convert-fiat-to-usd).
Virtual account funding is currently available in Naira only. Businesses in other countries can fund with crypto.
Collect each recipient's wallet address, the token they want (USDT or USDC), and its network (ERC20, TRC20, BASE, BSC, SOL, or TON).
Store these against the recipient in your own system, the same way you would store a bank account. Breet does not hold your recipient list; you pass the wallet details on each payout call, which means you can pay an unlimited number of recipients without registering any of them in advance.
Call [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) with the amount in USD, the recipient's wallet address, the token, the network, your transaction PIN, and your own reference in `externalId`.
Breet debits your USD balance, converts to the stablecoin, and broadcasts the transaction on-chain.
Every payout moves through a lifecycle, and Breet notifies you at each stage: `withdrawal.pending`, `withdrawal.completed`, `withdrawal.reversed`, or `withdrawal.rejected`.
The network fee is deducted from the amount you request, not added on top. If you request a \$100 payout on a network with a \$1 fee, your balance is debited \$100 and the recipient receives \$99. Check current fees with [`GET /payments/supported-assets-info`](/api-reference/assets/fetch-withdrawal-assets) before you send.
## Send a payout to a wallet address
```bash theme={null}
curl -X POST "https://api.breet.io/v1/payments/withdraw/address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"amount": 250,
"pin": "YOUR_PIN",
"walletAddress": "TXn8k2p9Rw4mQvL7yYc3sZ1bH6dJfE5aGx",
"token": "USDT",
"network": "TRC20",
"externalId": "payout-vendor-4471"
}'
```
A successful call returns the payout ID, which you can use with [`GET /payments/withdrawal/{id}`](/api-reference/withdrawals/fetch-withdrawal-by-id) at any time:
```json theme={null}
{
"message": "withdrawal initiated successfully",
"success": true,
"data": {
"id": "697251ed397a53d0cb7b228b"
}
}
```
## What Breet handles
* Converting your crypto or Naira balance into USD
* Converting USD into the stablecoin your recipient asked for
* Broadcasting the transaction on the network you specified
* Debiting your balance, and refunding it in full if a payout is reversed or rejected
* Delivering webhooks at every stage of the payout lifecycle
* Making the transaction hash and explorer link available once the payout confirms
## What you handle
* Keeping your balance funded ahead of a payout run
* Collecting and storing each recipient's wallet address, token, and network
* Validating that the address matches the network before you send
* Deciding when a payout is owed and triggering the withdrawal call
* Listening for webhooks and updating your own records
* Passing a unique `externalId` on every payout so you never send the same one twice
* Telling your recipients when their money is on the way and when it lands
## Example user journey
A Nigerian fintech funds its Breet balance using its Breet wallet address or assigned virtual account number.
1. The fintech converts its NGN balance to USD from the Breet dashboard.
2. Throughout the day, users request stablecoin withdrawals from their wallets on the app.
3. For each request, the backend calls [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) straight away, with the user's wallet address, the amount, the token, the network, and an `externalId` matching the request.
4. Breet debits the USD balance and sends each payout on-chain. Requests that come in at the same time are processed side by side, so no user waits behind another.
5. Breet sends a `withdrawal.pending` webhook for each payout, then `withdrawal.completed` with a transaction hash once it confirms.
6. Each request is marked as paid, and the fintech notifies its user.
## FAQ
Your available balance is the limit. There is no cap on how many payouts you send, or how often, and each request is processed independently so high-volume runs are not queued behind one another.
Deposit crypto to a Breet address, generated from your dashboard or over the API. You can also fund in Naira through the virtual account on your dashboard, then convert that balance with [`POST /payments/fiat-to-usd`](/api-reference/conversion/convert-fiat-to-usd).
USDT and USDC across ERC20, TRC20, BSC, SOL, BASE, and TON. Call [`GET /payments/supported-assets-info`](/api-reference/assets/fetch-withdrawal-assets) for the current list along with the fee on each network.
You are refunded in full. A payout that fails an internal check before broadcast comes back as `withdrawal.rejected`; one that is broadcast unsuccessfully comes back as `withdrawal.reversed`. In both cases the debited amount, including the fee, returns to your balance.
No. Once a payout is initiated, it cannot be cancelled through the API, because the transaction may already be broadcasting. Validate the address and amount before you call.
Payouts are near-instant in most cases. Speed depends on the network; Solana and Tron confirm almost immediately, while Ethereum can take longer when the network is congested.
# E-commerce
Source: https://docs.breet.io/use-cases/ecommerce
Add crypto checkout to your online store and auto-settle payments to your local bank account with the Breet API.
Add crypto as a payment method at checkout. Breet generates a unique wallet address per order, tracks the payment on-chain, and notifies your store when the transaction is confirmed so you can fulfill the order.
## How it works
When a customer selects crypto at checkout, call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint with the order ID as the `label`. This creates a dedicated deposit address tied to that order.
Show the wallet address, expected amount, and a QR code on your checkout page. The customer sends crypto from any wallet.
Breet sends a [webhook](/webhooks) when the payment is confirmed on-chain. Match the deposit to the order using the `label` or `destinationAddress`.
Once the webhook confirms full payment, update the order status and begin fulfillment.
How funds are handled after a payment depends on your setup:
* **Without auto-settlement**: payments are converted and held in your wallet in your chosen currency (USD, NGN, or GHS). You can view the balance on your dashboard and withdraw manually whenever you're ready.
* **With per-address auto-settlement**: each payment is automatically converted and paid out to the bank account linked to that specific address. Enable it via the API. See the [auto-settlement guide](/auto-settlement).
* **With business-wide auto-settlement**: all payments across all addresses are automatically withdrawn to a single destination (bank account). Enable it from your dashboard under **Settings > Automatic Settlement**.
You can set your preferred holding currency from the dashboard under **Settings > Crypto Settings**.
## Generate an address per order
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{"label": "order-98765"}'
```
Replace `ASSET_ID` with a [supported asset](/supported-assets) you want to accept for this order. The `label` field ties the address to your order ID, making reconciliation straightforward when the webhook arrives.
Generate a fresh address for every order. This makes it easy to match payments to orders without relying on amount matching.
## What Breet handles
* Generating unique wallet addresses per order
* Monitoring blockchains for incoming payments
* Sending webhook notifications with payment details
* Converting crypto to local fiat via auto-settlement
* Payouts to your business bank account
## What you handle
* Adding crypto as a payment option in your checkout flow
* Displaying the wallet address, amount, and QR code to the customer
* Listening for and processing webhook events
* Matching payments to orders using the `label` or address
* Handling order fulfillment after payment confirmation
* Managing underpayments or overpayments in your order logic
## Example user journey
1. Fatima adds items to her cart on an online store and proceeds to checkout.
2. She selects **Pay with crypto** and chooses USDT on Solana.
3. The store calls Breet's [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint with `label: "order-98765"` and displays the wallet address with the amount due.
4. Fatima sends the exact USDT amount from her wallet.
5. Breet detects the payment and sends a `trade.completed` webhook to the store's server.
6. The store matches the webhook to order 98765, marks it as paid, and begins shipping.
7. The crypto payment is held in the store's wallet balance (or auto-settled to the store's bank account if enabled).
## FAQ
Yes. Each call to the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint returns a unique wallet address. Pass your order ID in the `label` field so incoming payments are automatically mapped to the correct order when the webhook fires.
Breet reports the exact amount received in the webhook payload. If the amount is less than the order total, the webhook still fires with the partial amount. Your application should compare the received amount against the order total and decide how to handle it. You can prompt the customer to send the remaining balance, or cancel the order based on your business rules.
Yes. Crypto payments are borderless by nature. Any customer with a crypto wallet can send funds to the generated address regardless of their location. No additional configuration is needed for international payments.
Blockchain confirmation times vary by network. Fast networks like Solana typically confirm in seconds, while Bitcoin may take 5–60 minutes. Use the `trade.pending` webhook to show the customer that their payment has been detected, and `trade.completed` to confirm it. Consider setting a reasonable timeout and allowing customers to retry if the payment window expires.
# Fintech
Source: https://docs.breet.io/use-cases/fintech
Accept crypto and stablecoin deposits in your fintech app and auto-settle to local bank accounts with the Breet API.
Let your users fund wallets, savings accounts, or virtual cards with crypto and stablecoins. Breet generates deposit addresses, tracks incoming transactions, and notifies your app via webhooks so you can credit balances instantly.
## How it works
Call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint for a specific asset. Each address is permanent and unique to your user. You can also label the address using a unique identifier.
Display the wallet address in your app's funding flow. The user sends crypto from any external wallet.
When the transaction is detected on-chain, Breet sends a [webhook](/webhooks) to your server with the deposit details, amount, and status.
Parse the webhook payload, match it to the user, and credit their in-app balance.
This step is optional and depends on how you want to handle funds after a deposit:
* **Without auto-settlement**: deposits are converted and held in your wallet in your chosen currency (USD, NGN, or GHS). You can view the balance on your dashboard and withdraw manually whenever you're ready.
* **With per-address auto-settlement**: each deposit is automatically converted and paid out to the bank account linked to that specific address. Enable it via the API. See the [auto-settlement guide](/auto-settlement).
* **With business-wide auto-settlement**: all deposits across all addresses are automatically withdrawn to a single destination (bank account). Enable it from your dashboard under **Settings > Automatic Settlement**.
You can set your preferred holding currency from the dashboard under **Settings > Crypto Settings**. This determines the currency your wallet balance is held in when auto-settlement is off.
## Generate a deposit address
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{"label": "user-12345"}'
```
Replace `ASSET_ID` with the identifier for the crypto asset you want to accept (e.g., BTC, ETH, USDT). Use the `label` field to tag addresses with your internal user ID for easy reconciliation. Each address is **permanent**, so you only need to generate it once per user per asset. Store the address and display it whenever the user wants to deposit.
List available assets by calling [`GET /trades/assets`](/api-reference/assets/fetch-deposit-assets) to get valid asset IDs for your account.
## What Breet handles
* Generating and managing deposit wallet addresses
* Monitoring blockchains for incoming transactions
* Sending webhook notifications with transaction details
* Converting crypto to local fiat via auto-settlement
* Payouts to linked bank accounts
## What you handle
* Displaying the deposit address and instructions to your user
* Listening for and processing webhook events from Breet
* Mapping deposits to user accounts using the `label` or `destinationAddress`
* Crediting user balances in your application
* Communicating deposit status to your users
## Example user journey
1. Adeola opens her fintech app and taps **Fund account**.
2. She selects **USDT on Solana** as the funding method.
3. If this is Adeola's first deposit, the app calls Breet's [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint and stores the returned address. For future deposits, the app displays the same saved address since it is permanent.
4. Adeola copies the address and sends 50 USDT from her personal wallet.
5. Breet detects the transaction and sends a `trade.completed` webhook to the fintech app.
6. The app credits 50 USDT (or whatever equivalent) to Adeola's balance.
7. Adeola sees the funds in her account and can spend, save, or transfer them.
## FAQ
No. Breet operates entirely behind the scenes. Your users see your app's interface, branding, and messaging throughout the funding flow. Breet provides the infrastructure and you control the experience.
Yes. Call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint once per asset to create a separate deposit address for each currency. A single user can have addresses for BTC, ETH, USDT, and any other [supported asset](/supported-assets) simultaneously.
Deposit speed depends on blockchain confirmation times. Breet sends a `trade.pending` webhook as soon as the transaction is detected (mostly instantly), followed by `trade.completed` once it reaches the required number of confirmations. Most stablecoin deposits on fast networks like Solana complete within seconds.
Yes. Link a bank account to a wallet address and enable auto-settlement via [`PUT /trades/wallets/{id}/auto-settlement`](/api-reference/crypto-wallet/set-auto-settlement-status). Every deposit to that address will automatically convert to NGN or GHS and settle to the linked bank account. You can also enable business-wide auto-settlement from your dashboard. See the [auto-settlement guide](/auto-settlement) for the full details.
# Crypto off-ramping
Source: https://docs.breet.io/use-cases/offramp
Convert crypto and stablecoins to local currency and pay out to bank accounts in Nigeria and Ghana using the Breet API.
Let your users convert crypto holdings to local currency and withdraw to their bank accounts. Breet accepts crypto deposits, converts them at market rates, and settles directly to bank accounts in NGN or GHS. You provide the user experience, Breet handles the conversion and payout.
## How it works
Call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint for the asset the user wants to sell. Use the `label` field to tag the address with the user's ID. Each address is permanent, so you only need to generate it once per user per asset. Store it and reuse it for future off-ramps.
Display the wallet address in your app. The user sends BTC, ETH, USDT, or any other [supported asset](/supported-assets) from their personal wallet or exchange.
Breet detects the on-chain transaction and sends a [webhook](/webhooks) to your server with the deposit amount, asset, and status.
The deposit is automatically converted to your chosen wallet currency (USD, NGN, or GHS) at the current market rate.
How funds are handled after conversion depends on your setup:
* **Without auto-settlement**: the converted amount is held in your wallet in your chosen currency (USD, NGN, or GHS). You can view the balance on your dashboard and withdraw manually via [`POST /payments/withdraw/bank/{id}`](/api-reference/withdrawals/withdrawal-ngn-|-ghs) when ready.
* **With per-address auto-settlement**: each deposit is automatically paid out to the bank account linked to that specific address. Enable it via the API. See the [auto-settlement guide](/auto-settlement).
* **With business-wide auto-settlement**: all deposits across all addresses are automatically withdrawn to a single destination (bank account). Enable it from your dashboard under **Settings > Automatic Settlement**.
You can set your preferred holding currency from the dashboard under **Settings > Crypto Settings**.
## Generate a deposit address
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"label": "user-9201",
"bankId": "BANK_ID",
"accountNumber": "0123456789",
"narration": "Crypto off-ramp"
}'
```
Replace `ASSET_ID` with a valid asset ID from the [Fetch Deposit Assets](/api-reference/assets/fetch-deposit-assets) endpoint. The `bankId` comes from [`GET /payments/banks`](/api-reference/banks/fetch-bank-list). When bank details are included, the wallet is ready for [auto-settlement](/auto-settlement) once you enable it.
Pass bank details during address generation so you can enable auto-settlement immediately. See the [auto-settlement guide](/auto-settlement) for the full setup.
## Withdraw manually (without auto-settlement)
If you prefer to control when payouts happen, skip auto-settlement and initiate withdrawals yourself:
```bash theme={null}
curl -X POST "https://api.breet.io/v1/payments/withdraw/bank/BANK_ACCOUNT_ID" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"amount": 100,
"narration": "Off-ramp payout"
}'
```
The `amount` is in USD. Breet converts it to the local currency (NGN or GHS) based on the destination account's country.
## What Breet handles
* Generating deposit wallet addresses per user
* Monitoring blockchains for incoming transactions
* Converting crypto to fiat at current market rates
* Settling to bank accounts in NGN or GHS (via auto-settlement or manual withdrawal)
* Sending [webhook](/webhooks) notifications for every deposit and withdrawal status change
## What you handle
* Collecting the user's bank account details
* Displaying the deposit address and instructions in your app
* Listening for and processing webhook events
* Mapping deposits to users using the `label` or `destinationAddress`
* Communicating conversion status and payout confirmations to users
* Deciding whether to use auto-settlement or trigger withdrawals manually
## Example user journey
1. Emeka opens your app and selects **Cash out crypto**.
2. He chooses to sell USDT and enters the amount.
3. If this is Emeka's first off-ramp, your app calls Breet's [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint with his user ID as the label and his linked bank details, then stores the returned address. For future off-ramps, the app reuses the same address since it is permanent.
4. The app displays the USDT deposit address.
5. Emeka sends 200 USDT from his exchange account.
6. Breet detects the deposit and sends a `trade.completed` webhook to your server.
7. With auto-settlement enabled, Breet converts the USDT to NGN and pays out to Emeka's bank account.
8. Emeka receives the NGN in his bank and your app shows a confirmation.
## FAQ
Any asset Breet supports for your integration. See the full list on the [supported assets](/supported-assets) page, or call [`GET /trades/assets`](/api-reference/assets/fetch-deposit-assets) to get the current list for your account.
Breet currently supports bank payouts in **Nigeria (NGN)** and **Ghana (GHS)**.
That's up to your app's design. You can enable [auto-settlement](/auto-settlement) per address so payouts happen automatically, or hold funds in the wallet and let users trigger a withdrawal when they're ready. You can also offer both options.
Breet uses the current market rate at the time the deposit is confirmed. The converted amount appears in the webhook payload. If auto-settlement is enabled, the `rate` field shows the exact rate used.
With auto-settlement, bank payouts typically complete the same business day after the blockchain transaction is confirmed. Confirmation times depend on the network: stablecoins on Solana or Tron confirm in seconds, while Bitcoin may take longer.
Yes. You can set a markup percentage (0-10%) via the API or from your dashboard. The markup is deducted from each settlement as your revenue margin. See the [auto-settlement guide](/auto-settlement) for details.
# Crypto on-ramping
Source: https://docs.breet.io/use-cases/onramp
Buy stablecoins (USDT or USDC) with your Breet USD balance and send them to any external wallet address.
Use your Breet USD balance to purchase stablecoins and send them to any external wallet address. This is ideal for businesses that collect revenue in local currency (NGN or GHS), convert it to USD, and need to pay overseas suppliers, fund wallets, or move value on-chain.
## How it works
Your Breet account holds funds in USD. You can build up your USD balance in two ways:
* **Convert your existing NGN or GHS balance** to USD from the dashboard under **Settings > Crypto Settings** — this is the primary on-ramp path
* **Receive crypto deposits** that automatically convert to USD (see the [off-ramping](/use-cases/offramp) or [fintech](/use-cases/fintech) use cases)
Use [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to initiate a stablecoin purchase. Specify the amount in USD, the destination wallet address, the token (USDT or USDC), and the blockchain network.
Breet deducts the amount (plus network fee) from your USD balance and sends the stablecoins to the specified wallet address on the chosen network.
Breet sends a `withdrawal.completed` [webhook](/webhooks) once the transaction is confirmed on-chain. Listen for this event to update your system.
## Initiate a stablecoin withdrawal
```bash theme={null}
curl -X POST "https://api.breet.io/v1/payments/withdraw/address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"amount": 500,
"walletAddress": "0x1234...abcd",
"token": "USDT",
"network": "TRC20",
"externalId": "purchase-order-7891"
}'
```
| Parameter | Description |
| --------------- | ---------------------------------------------------------------------------------------- |
| `amount` | Amount in USD to spend on stablecoins |
| `walletAddress` | Destination wallet address for the stablecoins |
| `token` | `USDT` or `USDC` |
| `network` | Blockchain network: `ERC20`, `TRC20`, `BSC`, `SOL`, or `TON` (USDC not supported on TON) |
| `externalId` | Your unique reference for this transaction (for tracking and deduplication) |
Call [`GET /payments/supported-assets-info`](/api-reference/assets/fetch-withdrawal-assets) to see which tokens, networks, and fees are currently available before initiating a withdrawal. See the [supported assets](/supported-assets) page for the full list.
## What Breet handles
* Deducting the USD amount from your balance
* Sending stablecoins to the destination wallet on the specified network
* Handling blockchain transaction broadcasting and confirmation
* Sending [webhook](/webhooks) notifications for withdrawal status changes (`withdrawal.pending`, `withdrawal.completed`, `withdrawal.rejected`)
## What you handle
* Ensuring your Breet USD balance has sufficient funds
* Collecting and validating the destination wallet address
* Choosing the appropriate token and network for your use case
* Listening for webhook events to confirm delivery
* Communicating transaction status to your users or internal systems
## Example user journey
1. A Nigerian e-commerce company sends Naira to their Breet balance using their assign virtual account number.
2. The company converts their NGN balance to USD from the Breet dashboard.
3. On Friday, the company needs to pay an overseas supplier \$200,000 for inventory. The supplier accepts USDT on TRC20.
4. Their backend calls `POST /payments/withdraw/address` with the supplier's wallet address, amount 200,000, token USDT, network TRC20, and an `externalId` matching the purchase order.
5. Breet deducts 200,002 USD (plus a small network fee of \$2) from the company's balance and sends 200,000 USDT to the supplier's wallet.
6. Breet sends a `withdrawal.completed` webhook to the company's server.
7. The company's system marks the purchase order as paid and notifies the supplier.
## FAQ
USDT and USDC. See the [supported assets](/supported-assets) page for the full list of available tokens and networks.
ERC20 (Ethereum), TRC20 (Tron), BSC (BNB Smart Chain), SOL (Solana), and TON (The Open Network). Note that USDC is not available on TON.
You can view your balance on the [Breet API Dashboard](https://partners.breet.io) or call [`GET /integration`](/api-reference/account/fetch-account-details) to check your balance programmatically.
There are two ways: (1) receive crypto deposits that automatically convert to USD when your wallet currency is set to USD, or (2) convert your existing NGN or GHS balance to USD from the dashboard.
Yes. Each withdrawal incurs a network fee that varies by blockchain. Call [`GET /payments/supported-assets-info`](/api-reference/assets/fetch-withdrawal-assets) to see current fees per token and network.
Use the `externalId` you provided when creating the withdrawal. Listen for [webhooks](/webhooks) (`withdrawal.pending`, `withdrawal.completed`, `withdrawal.rejected`) or call [`GET /payments/withdrawal/{id}`](/api-reference/withdrawals/fetch-withdrawal-by-id) to check the status.
# OTC & P2P trading
Source: https://docs.breet.io/use-cases/otc-p2p
Use Breet as settlement infrastructure for OTC desks and P2P crypto trading platforms. Auto-settle trades to local bank accounts.
OTC desks and P2P trading platforms can use Breet as settlement infrastructure. Generate a unique deposit address per trade, monitor payments through [webhooks](/webhooks), and release funds after confirmation, giving you escrow-like control without building crypto infrastructure.
## How it works
When a trade is initiated, call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint with a label identifying the trade (e.g., a trade ID or order reference).
The buyer sends the agreed amount of crypto to the generated address. Your platform holds the trade in a pending state.
Breet monitors the blockchain and sends a [webhook](/webhooks) when the deposit is confirmed, including the amount and trade label.
After your platform confirms the trade conditions are met, release funds, either to the seller's bank account or to an external crypto address.
## Generate a deposit address for a trade
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"label": "trade-ord-78542"
}'
```
Replace `ASSET_ID` with a valid asset ID from the [Fetch Deposit Assets](/api-reference/assets/fetch-deposit-assets) endpoint. See the [supported assets](/supported-assets) page for a full list and the [quickstart](/quickstart) for authentication setup.
## What Breet handles
* Wallet address generation per trade
* Blockchain monitoring and deposit confirmation
* Webhook notifications with deposit details (amount, asset, label)
* Fiat settlement to bank accounts (NGN/GHS) when you trigger withdrawal
* Stablecoin withdrawals to external addresses
## What you handle
* Trade matching and order management between buyers and sellers
* Mapping each trade to a unique label for deposit tracking
* Listening for [webhooks](/webhooks) to update trade status (e.g., marking as funded)
* Deciding when to release funds (your escrow logic)
* Initiating withdrawals to the seller's bank or crypto address after trade completion
## Example user journey
1. A buyer and seller agree on a trade on your P2P platform.
2. Your backend calls Breet to generate a deposit address labeled with the trade ID.
3. Your platform shows the address to the buyer and holds the trade as "awaiting payment."
4. The buyer sends USDT to the deposit address.
5. Breet confirms the deposit and sends a webhook to your platform.
6. Your platform marks the trade as "funded" and notifies the seller.
7. The seller confirms delivery (or your platform auto-confirms based on your rules).
8. Your backend calls [`POST /payments/withdraw/bank/{id}`](/api-reference/withdrawals/withdrawal-ngn-|-ghs) or [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to release funds to the seller.
## FAQ
Yes. Generate a unique deposit address per trade so incoming funds are isolated. When Breet confirms the deposit via webhook, your platform controls when and how to release funds. You make the withdrawal call only after trade conditions are satisfied, giving you full escrow-like control.
Yes. Assign a unique `label` to each trade when generating the deposit address. Breet includes this label in all webhook payloads, so you can match deposits to specific trades even when handling hundreds of concurrent orders.
Yes. Use [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to send stablecoins (USDT/USDC) to an external wallet instead of settling to a bank account. This is useful when sellers prefer to receive crypto.
Breet reports the exact amount received in the webhook payload. Your platform is responsible for comparing this against the expected trade amount and deciding how to handle mismatches, such as requesting an additional payment or issuing a refund.
# Payroll
Source: https://docs.breet.io/use-cases/payroll
Pay remote employees and contractors across Africa with stablecoin-to-bank payouts using the Breet API. Fast, low-cost, no bank wires.
Pay remote employees and contractors in Africa without the delays and fees of traditional wire transfers. Load stablecoins into your Breet account, then withdraw directly to employees' bank accounts in NGN or GHS, or send stablecoins to their crypto wallets. Breet handles the conversion and payout so you can run payroll on your own schedule.
## How it works
Deposit USDT or USDC into your Breet wallet. You can generate a deposit address via the API or fund directly from your dashboard.
Collect each employee's bank account information (account number, bank name) or crypto wallet address. Store these in your payroll system.
Call the [withdraw-to-bank](/api-reference/withdrawals/withdrawal-ngn-|-ghs) endpoint for each employee. Breet converts the stablecoins to local currency and sends the payout to the employee's bank account.
Breet sends [webhook](/webhooks) notifications as each withdrawal progresses: `withdrawal.pending`, `withdrawal.completed`, `withdrawal.reversed`, or `withdrawal.rejected`.
## Withdraw to an employee's bank account
```bash theme={null}
curl -X POST "https://api.breet.io/v1/payments/withdraw/bank/BANK_ACCOUNT_ID" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{
"amount": 500,
"narration": "March 2026 salary - Jane Doe"
}'
```
Replace `BANK_ACCOUNT_ID` with the ID of the employee's saved bank account. The `amount` is in USD, and Breet converts it to the employee's local currency (NGN or GHS) based on their country. The `narration` is optional (max 32 characters) and appears on the bank statement.
To pay an employee in stablecoins instead, use [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) with their wallet address and the token amount.
## What Breet handles
* Converting stablecoins to NGN or GHS at current rates
* Processing bank payouts to employee accounts
* Sending webhook notifications for each withdrawal status change
* Processing crypto-to-wallet withdrawals for employees who prefer stablecoins
## What you handle
* Funding your Breet account with sufficient stablecoin balance
* Storing employee bank account details or wallet addresses
* Initiating individual withdrawal requests per employee
* Listening for and processing webhook events to confirm payout status
* Communicating payout confirmations to employees
* Scheduling and automating payroll runs on your preferred cadence
## Example user journey
1. A remote-first startup employs five contractors across Nigeria and Ghana.
2. On the last Friday of the month, the finance team triggers a payroll run from their internal tool.
3. The tool calls Breet's [withdraw-to-bank](/api-reference/withdrawals/withdrawal-ngn-|-ghs) endpoint for each contractor with their bank account ID, amount, and a narration like "March 2026 salary."
4. Breet converts the USDT to NGN or GHS and initiates bank transfers.
5. Each contractor receives a `withdrawal.completed` webhook, and the tool marks the payout as confirmed.
6. Contractors see the funds in their bank accounts within minutes.
7. The finance team reviews a summary of all payouts and statuses in their dashboard.
## FAQ
Breet processes withdrawals individually. To run payroll, make a separate withdrawal request for each employee. You can call the API programmatically in a loop or batch from your payroll system. All requests are processed concurrently on Breet's side.
Employees with bank accounts in Nigeria receive NGN. Employees in Ghana receive GHS. If an employee prefers stablecoins, use [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins) to send USDT or USDC directly to their crypto wallet.
Yes. Since all payouts are made via API, you can call the withdrawal endpoints programmatically on any schedule (weekly, biweekly, or monthly). Integrate with your existing payroll system or build a simple cron job that triggers withdrawals on payday.
Breet sends [webhooks](/webhooks) for every withdrawal status change. Listen for `withdrawal.completed` to confirm a successful payout, `withdrawal.reversed` if the bank returned the funds, or `withdrawal.rejected` if it failed. You can also call [`GET /payments/withdrawal/{id}`](/api-reference/withdrawals/fetch-withdrawal-by-id) to check withdrawal status at any time.
# SaaS & digital goods
Source: https://docs.breet.io/use-cases/saas-digital-goods
Accept crypto payments for SaaS subscriptions and digital products. Auto-settle to your bank account with the Breet API.
Accept crypto and stablecoin payments for subscriptions, licenses, and digital products. Breet generates a deposit address per invoice or subscription, tracks incoming transactions, and notifies your app via webhooks so you can activate access instantly. This opens your product to global customers who may not have access to traditional payment methods.
## How it works
Call the [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint when a customer initiates a purchase or subscription. Use the invoice or subscription ID as the `label` to link the payment to the order.
Show the deposit address and expected amount on your checkout or billing page. The customer sends crypto from any external wallet.
When the customer sends crypto, Breet detects the on-chain transaction and sends a [webhook](/webhooks) to your server with the amount, asset, and status.
Parse the webhook payload, match it to the invoice using the `label` or `destinationAddress`, verify the amount, and grant access.
How funds are handled after a payment depends on your setup:
* **Without auto-settlement**: payments are converted and held in your wallet in your chosen currency (USD, NGN, or GHS). You can view the balance on your dashboard and withdraw manually whenever you're ready.
* **With per-address auto-settlement**: each payment is automatically converted and paid out to the bank account linked to that address. Enable it via the API. See the [auto-settlement guide](/auto-settlement).
* **With business-wide auto-settlement**: all payments across all addresses are automatically withdrawn to a single destination (bank account). Enable it from your dashboard under **Settings > Automatic Settlement**.
You can set your preferred holding currency from the dashboard under **Settings > Crypto Settings**.
## Generate a payment address
```bash theme={null}
curl -X POST "https://api.breet.io/v1/trades/sell/assets/ASSET_ID/generate-address" \
-H "x-app-id: YOUR_APP_ID" \
-H "x-app-secret: YOUR_APP_SECRET" \
-H "X-Breet-Env: production" \
-H "Content-Type: application/json" \
-d '{"label": "inv-20260301-0042"}'
```
Replace `ASSET_ID` with the identifier for the crypto asset you want to accept (e.g., USDT, USDC). See the [supported assets](/supported-assets) page for the full list. Use the `label` field to tag the address with your invoice or subscription ID for easy reconciliation.
List available assets by calling [`GET /trades/assets`](/api-reference/assets/fetch-deposit-assets) to get valid asset IDs for your account.
## What Breet handles
* Generating deposit addresses tied to invoices or subscriptions
* Monitoring blockchains for incoming payments
* Sending webhook notifications with transaction details
* Converting crypto to local fiat via auto-settlement
* Payouts to linked bank accounts
## What you handle
* Creating invoices and mapping them to deposit addresses
* Displaying payment instructions and the deposit address at checkout
* Listening for and processing webhook events
* Verifying payment amounts against invoice totals
* Activating subscriptions or delivering digital goods after confirmation
* Handling underpayments, overpayments, or expired invoices
## Example user journey
1. Chinwe selects a yearly plan for your SaaS product and chooses **Pay with crypto** at checkout.
2. Your app creates an invoice and calls Breet's [generate-address](/api-reference/crypto-wallet/generate-wallet-address) endpoint with the invoice ID as the label.
3. The checkout page displays a USDT deposit address, the expected amount, and a QR code.
4. Chinwe sends the exact amount from her personal wallet.
5. Breet detects the transaction and sends a `trade.completed` webhook to your server.
6. Your app verifies the payment amount, marks the invoice as paid, and activates Chinwe's subscription.
7. Chinwe receives a confirmation email and gets immediate access to the product.
## FAQ
Yes. Use the `label` field when generating a deposit address to tag it with your invoice or subscription ID. When a webhook fires, match the `destinationAddress` or `label` back to the invoice in your system.
For each billing cycle, generate a new deposit address with the new invoice ID as the label. Alternatively, reuse an existing address if you track payments by amount and timing. Send your customer the address and expected amount ahead of each renewal.
Yes. Crypto payments are borderless. Any customer with a crypto wallet can pay, regardless of their location. This makes Breet a strong option for reaching global customers who may not have access to cards or local payment methods.
Breet reports the exact amount received in the webhook payload. Your app is responsible for comparing the received amount to the invoice total and deciding how to proceed. You can prompt the customer to send the remaining balance, issue a partial credit, or reject the payment.
# Webhooks
Source: https://docs.breet.io/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.
**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.
## 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. |
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.
### 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 to the destination account, after the withdrawal fee is deducted when the fee bearer is `user`. |
| `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.feeBearer` | string | Who absorbed the withdrawal fee — `user` (deducted from the payout) or `business` (added to the amount debited from your balance). Bank withdrawals only. See [Who bears the fee](/withdrawals#who-bears-the-fee-on-bank-withdrawals). |
| `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:
```
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.
Keep your webhook secret secure. Do not expose it in public repositories, client-side code, or logs.
### 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.
The API endpoints below require an active integration with API access (VIP partners). For full request/response schemas, see [List outgoing webhook events](/api-reference/webhooks/list-outgoing-webhook-events), [Get a single webhook event](/api-reference/webhooks/get-a-single-webhook-event), and [Resend all webhooks for a reference](/api-reference/webhooks/resend-all-webhooks-for-a-reference).
### 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.
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.
# Withdrawals
Source: https://docs.breet.io/withdrawals
A detailed explanation concerning what happens end-to-end when you withdraw stablecoins or fiat from Breet to an external wallet address or bank account.
A **withdrawal** moves funds out of your Breet wallet. The Partners API supports two types:
* **Stablecoin withdrawals** to an external wallet address — [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins). USDT and USDC on Ethereum, Tron, BSC, Solana, and TON (TON is USDT-only). Debited from your USD balance.
* **Bank withdrawals** to an NGN or GHS bank account — [`POST /payments/withdraw/bank/{id}`](/api-reference/withdrawals/withdrawal-ngn-|-ghs). Debited from your local-currency balance.
Both types share the same lifecycle and webhook events. This page focuses on stablecoin withdrawals; bank withdrawals differ in destination, currency, and [who bears the fee](#who-bears-the-fee-on-bank-withdrawals). For automatic bank payouts tied to deposits, see [Auto-settlement](/auto-settlement).
## Withdrawal states
| State | What it means |
| ----------- | ------------------------------------------------------------------------------------------------ |
| `pending` | Request accepted, your USD balance **debited in full**, queued for processing. Not yet on-chain. |
| `completed` | Broadcast succeeded and confirmed on-chain. `txHash` is populated. Balance stays debited. |
| `reversed` | Broadcast was attempted but was unsuccessful. **Balance refunded in full.** |
| `rejected` | Failed an internal check before broadcast. Not sent on-chain. **Balance refunded in full.** |
Each state change fires a webhook: `withdrawal.pending`, `withdrawal.completed`, `withdrawal.reversed`, or `withdrawal.rejected`.
**Rejected ≠ reversed.** Both refund your balance, but `rejected` means Breet blocked the withdrawal before it touched the blockchain; `reversed` means the transaction came back with a failure after an attempt to broadcast it. Only `withdrawal.completed` means the funds are on-chain at the destination.
## Withdrawal assets (mainnet)
Withdrawals to external crypto addresses only support **stablecoins** (USDT and USDC).
| Network | USDT | USDC |
| --------------------- | ---- | ---- |
| Ethereum (ERC20) | Yes | Yes |
| Tron (TRC20) | Yes | Yes |
| BNB Smart Chain (BSC) | Yes | Yes |
| Solana | Yes | Yes |
| TON | Yes | No |
For testnet IDs and the full deposit/withdrawal asset catalog, see [Supported assets](/supported-assets).
## Before you can withdraw
| Requirement | Detail |
| ------------------------ | ----------------------------------------------------------------------------------------------- |
| Active credentials | Valid `x-app-id` / `x-app-secret`, integration in `active` state. |
| Funded USD wallet | Balance ≥ `amount`. The full `amount` is debited at request time and the `fee` comes out of it. |
| PIN set | The `pin` field is required in the request body. Set or rotate it from the dashboard. |
| Account in good standing | Suspended or frozen accounts are blocked. |
| IP allowlist (optional) | If configured on your integration, the request must come from an allowed IP. |
## Happy path
Call [`POST /payments/withdraw/address`](/api-reference/withdrawals/withdraw-stable-coins):
```json theme={null}
{
"amount": 100,
"token": "USDT",
"network": "TRC20",
"walletAddress": "TRecipientTronAddressHere...",
"pin": "1234",
"externalId": "your-internal-id-123"
}
```
| Field | Notes |
| --------------- | ------------------------------------------------------------------------- |
| `amount` | USD value, up to 2 decimal places. Subject to your integration's min/max. |
| `token` | `USDT` or `USDC`. |
| `network` | `ERC20`, `TRC20`, `BSC`, `SOL`, or `TON` (TON supports USDT only). |
| `walletAddress` | Valid address for the network. Cannot be a Breet-managed address. |
| `pin` | Required even for server-to-server calls. |
| `externalId` | Optional. Your reference, useful for matching webhooks. |
Breet responds synchronously with the withdrawal `id`.
Synchronous checks, in order:
1. Credentials and integration active.
2. IP in allowlist (if configured).
3. PIN is correct. Repeated wrong PINs can temporarily freeze the account.
4. `amount` within min/max.
5. Address is valid for the network and not a Breet-managed address.
6. Not a duplicate request.
7. Balance ≥ `amount`.
All pass → `amount` is debited, withdrawal is created with `status: pending`, `withdrawal.pending` webhook is queued.
Any fail → no record, no debit, no webhook. You receive an HTTP error. See [Error handling](/errors).
Approval is mostly automatic. The transaction is signed and broadcast on the chosen network. The recipient receives `amount − fee` on-chain (see [Fees](#fees-and-minimums)).
Withdrawals flagged for internal review may stay in `pending` until Breet approves (typically within a few minutes).
Once the withdrawal is successful, `withdrawal.completed` fires with the on-chain `txHash`.
## Webhook sequence, by scenario
| Scenario | Events (same `id`) |
| --------------------- | ------------------------------------------------------- |
| Clean withdrawal | `withdrawal.pending` → `withdrawal.completed` |
| Blocked pre-broadcast | `withdrawal.pending` → `withdrawal.rejected` (refunded) |
| Broadcast failed | `withdrawal.pending` → `withdrawal.reversed` (refunded) |
Webhook delivery is asynchronous and ordering isn't guaranteed under variable endpoint latency. Trust the `event` and `status` fields on each payload, not the order they arrive in.
## Fees and minimums
Breet charges a **small flat fee per crypto** to cover the network fee. The fee is shown on the webhook payload as `fee`.
The `fee` is **deducted from** the `amount` you request. Your balance is debited the full `amount`, and the recipient receives `amount − fee` on-chain.
**Example.** You call with `amount: 100`, USDT on Tron, fee `$1`. Your balance is debited **\$100**. The recipient receives **\$99 of USDT on Tron**.
## Who bears the fee on bank withdrawals
Bank withdrawals carry a flat fee per payout, set per destination currency. Read the fee that currently applies to your integration from [`GET /users/fetch-integration`](/api-reference/account/fetch-account-details) as `withdrawalFee`:
```json theme={null}
"withdrawalFee": {
"ngn": 50,
"ghs": 1
}
```
You choose which side of the payout it comes out of with the `withdrawalFeeBearer` setting on your integration.
| `withdrawalFeeBearer` | Debited from your balance | Recipient is credited | Use when |
| --------------------- | ------------------------- | --------------------- | ---------------------------------------------------- |
| `user` (default) | `amount` | `amount − fee` | You pass the fee on to your end-user. |
| `business` | `amount + fee` | `amount` | You absorb the fee so your end-user is paid in full. |
**Example.** A ₦50,000 payout with a ₦50 fee:
* `user` — your balance is debited **₦50,000**, the destination account is credited **₦49,950**.
* `business` — your balance is debited **₦50,050**, the destination account is credited **₦50,000**.
Breet charges the fee exactly once either way. The setting only decides who absorbs it, never how much it is.
This setting applies to bank withdrawals and to [auto-settlement](/auto-settlement) payouts, both of which pay out to an NGN or GHS bank account. Stablecoin withdrawals are unaffected — their network fee is always deducted from the `amount`, as described above.
### Set the fee bearer
Set this from the **Business** tab on the **Developer** page in your [dashboard](https://partners.breet.io). The new value applies to withdrawals created after you save it — a withdrawal already in `pending` keeps the pricing it was created with.
The [`GET /users/fetch-integration`](/api-reference/account/fetch-account-details) response returns the current setting as `withdrawalFeeBearer`, and every bank withdrawal records the bearer that applied to it as `meta.feeBearer`, so you can reconcile a payout against the setting that was live when it was created.
## Fetching withdrawals via the API
| Purpose | Endpoint |
| ---------------- | ------------------------------------------------------------------------------------ |
| List withdrawals | [`GET /payments/withdrawals`](/api-reference/withdrawals/fetch-withdrawals) |
| Fetch one by ID | [`GET /payments/withdrawal/{id}`](/api-reference/withdrawals/fetch-withdrawal-by-id) |
On every webhook, fetch the withdrawal by `id` before updating your system of record. Combined with [IP and secret verification](/webhooks#webhook-verification), this is defence in depth.
## FAQ
No. The Partners API supports only stablecoin withdrawals (USDT, USDC) on the networks listed above. To move native coins, sell them via a deposit first, then withdraw as a stablecoin.
Not via API. Contact support immediately after submitting if it's critical. Once approved and broadcast, the withdrawal can only complete or reverse.
On-chain transactions are irreversible. Breet validates address **format**, not ownership. Always confirm the destination with your end-user before submitting.
Seconds/Minutes on Solana, Tron, and TON. Longer on EVM chains due to confirmation times.
It's an additional verification layer in case your API keys leak. Store the PIN alongside your secrets and rotate it from the dashboard if exposed.
## Next steps
* Set up webhook handling → [Webhooks](/webhooks)
* See supported withdrawal networks and tokens → [Supported assets](/supported-assets)
* Handle 429s correctly → [Rate limiting](/rate-limiting)
* Simulate a withdrawal on testnet → [Testing](/testing)