Skip to main content
The withdrawal-address whitelist is an opt-in, per-wallet allowlist of destination addresses. It is independent of 2FA — the two features stack, but neither implies the other — and the same endpoints serve the frontend (Privy JWT) and API-key integrators.
Opt-in. With zero entries the whitelist is not configured and withdrawals are unrestricted by destination. Add one entry and the wallet flips to allowlist mode: from then on, withdrawals are permitted only to listed addresses.
No cooldown. A freshly-added address is usable on the very next withdrawal — there is no aging/activation delay.

When it is enforced

The destination check at withdraw time runs only when the platform has withdrawal-security enforcement enabled (a server-side flag, off by default during rollout) and the caller is not a partner_sso integration (exempt). You can manage the list at any time regardless of enforcement. This whitelist is a separate control from the AML / sanctions screen and the high-value review routing, which always run in withdrawal review. (The legacy return-to-source / cleared-deposit-source gate was retired — CP-D3, 2026-05-22.)

Endpoints

Method & pathScopeRate limitPurpose
GET /api/me/withdrawal-security/whitelistportfolio:read60/minList entries (newest first)
POST /api/me/withdrawal-security/whitelistvault:write30/minAdd an entry
DELETE /api/me/withdrawal-security/whitelist/{id}vault:write30/minRemove an entry
For multi_wallet API keys every call needs the X-User-Wallet header naming the acting wallet.

Listing

GET /api/me/withdrawal-security/whitelist
{
  "addresses": [
    {
      "id": "8f1c…-uuid",
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "label": "My Ledger",
      "createdAt": "2026-06-16T12:00:00.000Z"
    }
  ]
}
An empty addresses array means the whitelist is not configured (unrestricted withdrawals).

Adding

POST /api/me/withdrawal-security/whitelist
{ "address": "0x1234…", "label": "My Ledger" }
address
string
required
Destination EVM address (0x + 40 hex). Any case is accepted (lowercase, uppercase-hex, or EIP-55 checksum) and stored lowercase — the EIP-55 checksum is irrelevant. Invalid format → 400 invalid_address.
label
string
Optional human label (≤ 100 chars), e.g. "My Ledger".
Returns the created entry (201). Constraints:
  • Duplicate (wallet, address)409 address_already_whitelisted.
  • Cap of 50 entries per wallet → 409 whitelist_limit_reached.
Add/remove are plain authenticated calls (no 2FA). The 2FA gate at withdraw time is what authorises moving funds, so a hijacked session that adds an address still cannot withdraw to it without the authenticator (when 2FA is active).

Removing

DELETE /api/me/withdrawal-security/whitelist/{id} removes one entry by its id, scoped to the owner. Unknown / non-owned id → 404 whitelist_address_not_found. Returns 204 No Content.

At withdraw time

When the whitelist is configured, the withdraw request’s destination (POST /api/withdrawals/request) must match a listed address (case-insensitive), otherwise:
CodeHTTPWhen
withdrawal_address_not_whitelisted403Whitelist configured and destination is not on it

API-key callers

A multi_wallet partner manages the list per end-user wallet via X-User-Wallet + vault:write. On the very first request for a freshly-seen wallet, add may return 409 account_provisioning while partner-backed onboarding finishes writing the user record — transient, retry after a moment.

Next

Withdrawal 2FA

The TOTP second factor that stacks with the whitelist.

Withdrawals overview

The full dual-sig withdrawal flow.

Error codes

Every withdrawal-security code in one table.

API reference

Withdrawal Security endpoints.