Create a Crypto Withdrawal
Sends crypto from an account's balance to one of its counterparties. The amount is reserved on the balance at once, moving from its available to its pending_debits, and the withdrawal starts pending. For five minutes, until grace_ends_at, it can be cancelled; then it is submitted to the custodian and sent to the network.
The fee is computed again here, as Preview a Crypto Withdrawal computes it: the counterparty receives amount minus fee.
Part of crypto v3, in beta. While crypto v3 withdrawals are off for the account, this answers 404 feature_not_enabled.
A workspace-scoped key names the account with account_id; an account-scoped key acts for its own account.
Replaces POST /api/v2/crypto/withdraw.
Authorization:
Every request is signed with your API key: a short-lived JWT, signed with your private key, sent in one header on /v3/* and /api/v2/* alike.
Headers:
Authorization: APIKey {SIGNED_JWT}
How to build and sign the JWT: Authentication.
Endpoint
/v3/crypto/withdrawals
Headers
| Header | Description |
|---|---|
Idempotency-Key | Required. One key per withdrawal you mean to make: any printable-ASCII string of 1 to 255 characters (a UUID is recommended), sent again unchanged on every retry of it. A retry answers the first response, with Idempotency-Replayed: true, instead of sending the money twice. Dashboard sessions are held to it already; API keys have a grace period until 2027-01-18, during which a request without it still runs and its response carries a Warning header. See Safe retries. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
account_id | string (cst_…) | The account to withdraw from. Required for a workspace-scoped key; an account-scoped key may omit it. |
Request Body Sample
{
"counterparty_id": "wlt_01k8z5q7r9s1t3v5w7x9y1z3a5",
"coin": "USDC",
"amount": "250",
"reference": "inv-2026-10-0042",
"description": "Supplier payment",
"preview_id": "wtx_01k9a0x2y4z6a8b0c2d4e6f8g0"
}
Request Body Schema
| Field | Type | Description |
|---|---|---|
counterparty_id | string (wlt_…) | Required. One of the account's counterparties. |
coin | string | Required. The coin to send: the counterparty's coin. Any casing. |
amount | string (decimal) | Required. How much to withdraw, in the coin, greater than zero, as a decimal string. |
reference | string | Required. Your own reference for the withdrawal, 1 to 255 characters. It need not be unique. |
description | string | Optional. Up to 255 characters. |
preview_id | string | Optional. The id of the preview you showed, up to 64 characters. Recorded only: the amounts are computed again. |
Response Sample
200 OK
{
"id": "wtx_01k9a1b3c5d7e9f1g3h5j7k9m1",
"account_id": "cst_01h455vb4pex5vsknk084sn02q",
"status": "pending",
"coin": "USDC",
"amount": "250",
"fee": "10",
"total": "240",
"counterparty_id": "wlt_01k8z5q7r9s1t3v5w7x9y1z3a5",
"counterparty_address": "0x8f3b2c1d0e9a7b6c5d4e3f2a1b0c9d8e7f6a5b4c",
"reference": "inv-2026-10-0042",
"description": "Supplier payment",
"status_reason": "Withdrawal created, waiting for grace period",
"grace_ends_at": "2026-10-20T18:05:00Z",
"created_at": "2026-10-20T18:00:00Z",
"updated_at": "2026-10-20T18:00:00Z"
}
Response Schema
| Field | Type | Description |
|---|---|---|
id | string (wtx_…) | The withdrawal. Keep it: v3 has no list of withdrawals yet. |
account_id | string (cst_…) | The account it is sent from. |
status | string | See The life of a withdrawal. |
coin | string | The coin, upper case. |
amount | string (decimal) | What leaves the balance; reserved from the moment it is created. |
fee | string (decimal) | What the account pays, inside amount. |
total | string (decimal) | What the counterparty receives: amount minus fee. |
counterparty_id | string (wlt_…) | The counterparty. |
counterparty_address | string | The address it is sent to, without the memo, as it was when the withdrawal was created. |
reference | string | As sent. |
description | string | As sent; absent when empty. |
status_reason | string | Why the withdrawal is where it is, in words. For people: branch on status. |
provider | string | The custodian that sends it. Absent until it is submitted. |
external_id | string | The custodian's id for the transfer. Absent until it is submitted. |
tx_hash | string | The network transaction hash. Absent until the network has it. |
grace_ends_at | string (date-time) | Until when it can be cancelled. |
created_at / updated_at | string (date-time) | RFC 3339, UTC. |
Amounts are decimal strings in the coin, without trailing zeros (see Amounts).
The life of a withdrawal
status | What happened | The account's balance |
|---|---|---|
pending | Created; waiting out the grace period. Can be cancelled. | amount moved from available to pending_debits |
processing | Submitted to the custodian. | still in pending_debits |
confirmed | Broadcast to the network, waiting for confirmations. | still in pending_debits |
success | Completed. | amount leaves pending_debits: debited |
failed | The custodian refused it or it failed on the way. | amount back from pending_debits to available |
cancelled | Cancelled during the grace period. | amount back from pending_debits to available |
The crypto_transaction_created webhook is sent when it is created, and crypto_transaction_status_updated when it reaches processing, success, failed or cancelled; follow the other steps with Get a Crypto Withdrawal.
Errors
| Status | message | When |
|---|---|---|
400 | account_id_required | A workspace-scoped key named no account_id. |
400 | invalid_account_id | account_id is not a cst_… id. |
400 | failed to parse request | The body is not valid JSON, counterparty_id is not a wlt_… id, coin is not a ticker, or amount is not a decimal. |
400 | invalid_coin | coin is a fiat currency, such as USD. |
400 | invalid_amount | amount is missing, zero or negative. |
400 | counterparty_coin_mismatch | coin is not the counterparty's coin. |
400 | idempotency_key_required | No Idempotency-Key header (dashboard sessions now; API keys once the grace period ends). |
400 | idempotency_key_invalid | The Idempotency-Key is longer than 255 characters or not printable ASCII. |
401 | unauthorized | Missing or invalid signature. |
403 | forbidden | An account-scoped key named another account. |
403 | account_frozen | The account is frozen or blocked. |
404 | feature_not_enabled | Crypto v3 withdrawals are not enabled for the account. See Turning it on. |
404 | customer_not_found | account_id names no account of the workspace. |
404 | counterparty_not_found | counterparty_id is missing, names no counterparty, or names another account's or a deleted one. |
409 | idempotency_in_progress | The same Idempotency-Key is still running. Retry after Retry-After seconds with the same key. |
413 | body_too_large | The body is over 1 MiB. |
422 | withdrawal_below_minimum | amount is below the minimum withdrawal for this coin. |
422 | withdrawal_coin_unsupported | BlockWyre cannot send this coin. Nothing was reserved. |
422 | insufficient_balance | The account's available balance in this coin does not cover amount. |
422 | Validation failed | coin or reference is missing, or a text field is longer than allowed; details names it. |
422 | idempotency_key_conflict | The same Idempotency-Key was used for a different request. |
503 | idempotency_unavailable | The retry store could not be reached. Nothing was created: retry later with the same key. |
Coming from v2
v2 (POST /api/v2/crypto/withdraw) | v3 |
|---|---|
| no idempotency header | Idempotency-Key required (API keys: grace period until 2027-01-18) |
accountId in the body | account_id in the query, optional for an account-scoped key |
beneficiaryId, previewId | counterparty_id (wlt_…), preview_id |
answers { "transactionId": … } | answers the whole withdrawal; id is the same id as a TypeID (wtx_…) |
| cancelled through v2 | cancelled through v3 only: v2's cancel refuses a v3 withdrawal with 409 |
Support and Resources
If you need assistance or have any questions, our support team is here to help. You can contact our support team at support@blockwyre.com.
Stay Updated
Stay up-to-date with the latest news, updates, and features from BlockWyre by following us on social media:
- Instagram: BlockWyre Instagram
- Twitter: BlockWyre Twitter
- Facebook: BlockWyre Facebook
- LinkedIn: BlockWyre LinkedIn
We are excited to have you on board and look forward to seeing how you leverage BlockWyre's powerful tools to enhance your financial operations. Happy integrating!