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

# 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 only in destination and currency. 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`.

<Warning>
  **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.
</Warning>

## 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 + fee`. Both are debited together at request time.                  |
| 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

<Steps>
  <Step title="You submit the request">
    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`.
  </Step>

  <Step title="Breet validates and debits">
    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 + fee`.

    All pass → `amount + fee` 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).
  </Step>

  <Step title="Breet approves and broadcasts">
    Approval is mostly automatic. The transaction is signed and broadcast on the chosen network. The recipient receives the full `amount` on-chain — the `fee` is charged separately (see [Fees](#fees-and-minimums)).

    Withdrawals flagged for internal review may stay in `pending` until Breet approves (typically within a few minutes).
  </Step>

  <Step title="Breet confirms completion">
    Once the withdrawal is successful, `withdrawal.completed` fires with the on-chain `txHash`.
  </Step>
</Steps>

## 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) |

<Tip>
  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.
</Tip>

## 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**.

## 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) |

<Tip>
  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.
</Tip>

## FAQ

<AccordionGroup>
  <Accordion title="Can I withdraw BTC, ETH, SOL, or other native coins?">
    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.
  </Accordion>

  <Accordion title="Can I cancel a pending withdrawal?">
    Not via API. Contact support immediately after submitting if it's critical. Once approved and broadcast, the withdrawal can only complete or reverse.
  </Accordion>

  <Accordion title="What if I send to the wrong address?">
    On-chain transactions are irreversible. Breet validates address **format**, not ownership. Always confirm the destination with your end-user before submitting.
  </Accordion>

  <Accordion title="How quickly do withdrawals complete?">
    Seconds/Minutes on Solana, Tron, and TON. Longer on EVM chains due to confirmation times.
  </Accordion>

  <Accordion title="Why do I need a PIN for an API call?">
    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.
  </Accordion>
</AccordionGroup>

## 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)
