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

# Request a withdrawal

> Move a balance out to a destination you've already approved in your dashboard.

Moves a balance from your master wallet, or from one of your users' addresses, out to an external destination.

<Warning>
  Backend only. Never call from frontend.
</Warning>

Before you can withdraw, the destination address needs to be on your approved list, added from **Dashboard → Wallets → Settings**. This can't be done with an API key: a key that could both withdraw and approve its own destination would be able to empty a balance on its own.

## Endpoint

```text theme={null}
POST https://merchant.minisend.xyz/api/v1/withdrawals
```

```text theme={null}
Authorization: Bearer wsk_live_your_key_here
```

Requires the `withdraw` scope. This scope defaults off on every key, including keys created before scopes existed — turn it on explicitly for a key that should be able to move money.

## Body

<ParamField body="source" type="string" required>
  `"master"` to withdraw from your master wallet, or the `walletRef` of the address to withdraw from.
</ParamField>

<ParamField body="chain" type="string" required>
  The chain to withdraw on.
</ParamField>

<ParamField body="token" type="string" required>
  `USDC` or `USDT`.
</ParamField>

<ParamField body="amount" type="number" required>
  A positive number, in the token's units. Refused, not rounded, if it carries more decimal places than the token supports — rounding could silently send more than you asked for.
</ParamField>

<ParamField body="destination_address" type="string" required>
  Must already be on your approved destinations list for this account.
</ParamField>

<ParamField body="idempotency_key" type="string">
  Reusing the same key with the same request returns the original withdrawal instead of creating a second one. Reusing it with a different `source`, `chain`, `token`, `amount`, or `destination_address` is refused with `409`.
</ParamField>

## Example

```bash theme={null}
curl -X POST https://merchant.minisend.xyz/api/v1/withdrawals \
  -H "Authorization: Bearer wsk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "master",
    "chain": "BASE",
    "token": "USDC",
    "amount": 50,
    "destination_address": "0x9f2c000000000000000000000000000000dead"
  }'
```

## Response (202)

```json theme={null}
{
  "withdrawal": {
    "id": "9f2c4e1a-...",
    "state": "queued",
    "source": "master",
    "chain": "BASE",
    "token": "USDC",
    "amount": "50.000000",
    "destination_address": "0x9f2c000000000000000000000000000000dead",
    "tx_hash": null,
    "created_at": "2026-09-28T09:00:00.000Z",
    "updated_at": "2026-09-28T09:00:00.000Z"
  }
}
```

`202`, not `200`: the withdrawal is accepted and queued, and the transfer itself happens shortly after. Poll [get a withdrawal](/api-reference/wallet-api/get-withdrawal) or listen for [`wallet.withdrawal.completed`](/wallet-api/webhooks) to learn the outcome. Replaying an `idempotency_key` returns `200` with the original withdrawal instead.

<ResponseField name="state" type="string" required>
  `queued`, `sending`, `completed`, or `failed`.
</ResponseField>

<ResponseField name="source" type="string">
  Echoes what you sent: `"master"`, or the `walletRef` you withdrew from.
</ResponseField>

<ResponseField name="tx_hash" type="string">
  The on-chain transaction, once sent. `null` until then, and while `failed`.
</ResponseField>

## Listing your withdrawals

```text theme={null}
GET https://merchant.minisend.xyz/api/v1/withdrawals
```

Needs `wallets:read`.

<ParamField query="limit" default="20" type="number">
  Page size, max 100.
</ParamField>

<ParamField query="offset" default="0" type="number">
  Rows to skip.
</ParamField>

```json theme={null}
{
  "withdrawals": [ { "id": "9f2c4e1a-...", "state": "completed", "...": "..." } ],
  "total": 12,
  "limit": 20,
  "offset": 0
}
```

Each entry is the same shape as the response above.

## Errors

| Status | Meaning |
| - | - |
| `400` | Invalid body, amount below the chain's minimum, amount above your available balance, or the destination is one of your own addresses |
| `401` | Missing or invalid API key |
| `403` | The destination isn't on your approved list yet |
| `404` | No active wallet for that chain, or no address with that reference |
| `409` | The `idempotency_key` was already used with a different request, or that withdrawal was already submitted |
| `429` | Rate limit exceeded |
| `503` | Could not check your balance or submit the withdrawal right now. Retry |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.