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

# Withdrawal address whitelist

> Optional per-wallet allowlist restricting withdrawals to pre-approved destinations.

The withdrawal-address whitelist is an **opt-in, per-wallet** allowlist of
destination addresses. It is independent of [2FA](/concepts/withdrawals/two-factor)
— the two features stack, but neither implies the other — and the same
endpoints serve the frontend (Privy JWT) and API-key integrators.

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

<Tip>
  **No cooldown.** A freshly-added address is usable on the very next
  withdrawal — there is no aging/activation delay.
</Tip>

## 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 & path                                       | Scope            | Rate limit | Purpose                     |
| --------------------------------------------------- | ---------------- | ---------- | --------------------------- |
| `GET /api/me/withdrawal-security/whitelist`         | `portfolio:read` | 60/min     | List entries (newest first) |
| `POST /api/me/withdrawal-security/whitelist`        | `vault:write`    | 30/min     | Add an entry                |
| `DELETE /api/me/withdrawal-security/whitelist/{id}` | `vault:write`    | 30/min     | Remove an entry             |

For `multi_wallet` API keys every call needs the
[`X-User-Wallet`](/auth/api-keys) header naming the acting wallet.

## Listing

```json GET /api/me/withdrawal-security/whitelist theme={null}
{
  "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

```json POST /api/me/withdrawal-security/whitelist theme={null}
{ "address": "0x1234…", "label": "My Ledger" }
```

<ParamField body="address" type="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`.
</ParamField>

<ParamField body="label" type="string">
  Optional human label (≤ 100 chars), e.g. `"My Ledger"`.
</ParamField>

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`](/concepts/withdrawals/eip712#request)) must
match a listed address (case-insensitive), otherwise:

| Code                                 | HTTP | When                                                |
| ------------------------------------ | ---- | --------------------------------------------------- |
| `withdrawal_address_not_whitelisted` | 403  | Whitelist 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

<CardGroup cols={2}>
  <Card title="Withdrawal 2FA" icon="shield-halved" href="/concepts/withdrawals/two-factor">
    The TOTP second factor that stacks with the whitelist.
  </Card>

  <Card title="Withdrawals overview" icon="money-bill-transfer" href="/concepts/withdrawals/overview">
    The full dual-sig withdrawal flow.
  </Card>

  <Card title="Error codes" icon="triangle-exclamation" href="/errors/codes">
    Every withdrawal-security code in one table.
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/openapi">
    Withdrawal Security endpoints.
  </Card>
</CardGroup>
