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

# Withdraw Funds

> Preview, initiate, and track portfolio wallet withdrawals.

Portfolio wallet withdrawals are asynchronous. A withdrawal may involve unwinding yield positions, bridging across chains, and waiting for customer approval -- all orchestrated automatically.

<Note>
  Treat withdrawal creation as acceptance and reservation of a request, not as a universal price lock across every yield source. Morpho ERC-4626 vaults exposed by the live catalog are synchronous exits without a normal queue window. Syrup USDC and the U.S. Treasury Bill Vault are asynchronous exits: if the underlying protocol settles at a lower value before processing, the final payout can be lower than the amount originally requested. Syrup withdrawals can be partially processed while the remainder stays pending; U.S. Treasury Bill Vault redemptions progress through request, process, and claim stages as Superstate liquidity becomes available.
</Note>

## Withdrawal lifecycle

The typical flow is: **preview -> initiate -> track -> complete**.

1. **Preview** -- call `withdrawal-preview` to see what's available and get a sourcing plan.
2. **Initiate** -- call `withdrawals` to create the withdrawal. The system reserves liquidity and begins sourcing.
3. **Track** -- poll the withdrawal or subscribe to webhooks. The withdrawal moves through statuses as positions unwind, funds bridge, and payouts execute.
4. **Complete** -- the withdrawal reaches `completed` when all funds have been delivered.

## Preview a withdrawal

Before initiating, preview what balance is available for a given destination.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "$BASE_URL/v2/wallets/$WALLET_ID/withdrawal-preview" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destinationChain": "polygon",
    "amountUsd": 65000,
    "token": "usdc"
  }'
```

| Field              | Required | Description                                                                                                   |
| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------- |
| `destinationChain` | Yes      | Destination chain for the withdrawal                                                                          |
| `amountUsd`        | No       | Amount to preview as a number (max 6 decimal places). If omitted, previews the maximum available balance.     |
| `token`            | Yes      | Token to deliver: `usdc` or `usdt`. USDT is Ethereum-only in production and Ethereum Sepolia-only in sandbox. |

With an explicit `amountUsd`, `amountRequestedUsd` echoes the requested amount:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "amountRequestedUsd": "65000.000000",
  "feeUsd": "0.000000",
  "withdrawableUsd": "82500.000000",
  "totalUsdAfterWithdrawal": "35000.000000",
  "estimatedCompletionTime": "PT2H",
  "maxCompletionTime": "PT4H"
}
```

When `amountUsd` is omitted, the preview reflects the maximum available balance and `amountRequestedUsd` is `null`:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "amountRequestedUsd": null,
  "feeUsd": "0.000000",
  "withdrawableUsd": "82500.000000",
  "totalUsdAfterWithdrawal": "17500.000000",
  "estimatedCompletionTime": "PT2H",
  "maxCompletionTime": "PT4H"
}
```

| Field                     | Description                                                                                                                              |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `amountRequestedUsd`      | The withdrawal amount previewed (equals the requested amount, or `null` when `amountUsd` was omitted and the max available is previewed) |
| `feeUsd`                  | Fee for the withdrawal (currently always `"0.000000"`)                                                                                   |
| `withdrawableUsd`         | Conservative amount that can safely start a new withdrawal for this destination right now                                                |
| `totalUsdAfterWithdrawal` | Estimated wallet total after the previewed withdrawal amount is paid out                                                                 |
| `estimatedCompletionTime` | Estimated end-to-end completion time as an ISO 8601 duration                                                                             |
| `maxCompletionTime`       | Worst-case (SLA upper bound) end-to-end completion time as an ISO 8601 duration                                                          |

`withdrawableUsd` on the wallet object and in preview are related but different:

* Wallet `withdrawableUsd` is the wallet-level conservative amount that can be withdrawn now.
* Preview `withdrawableUsd` is the destination-specific amount that can safely start right now.
* Preview `withdrawableUsd` can be lower than the wallet object's `withdrawableUsd`.

Ground keeps wallet-level ownership, wallet-level readiness, and destination-specific readiness separate on purpose. Value can remain customer-owned while still being unavailable to start a fresh withdrawal to a specific destination, for example when a prior unwind, bridge, or payout boundary is still settling and the destination representation has not yet been observed.

## Initiate a withdrawal

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "$BASE_URL/v2/wallets/$WALLET_ID/withdrawals" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "df8b7be6-e110-4f6d-9b2d-7c44a5b1f0b0",
    "destinationChain": "ethereum",
    "amountUsd": 65000,
    "token": "usdc",
    "destinationAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
  }'
```

| Field                | Required | Description                                |
| -------------------- | -------- | ------------------------------------------ |
| `requestId`          | Yes      | UUID v4 idempotency key                    |
| `destinationChain`   | Yes      | Destination chain                          |
| `amountUsd`          | Yes      | Amount as a number (max 6 decimal places)  |
| `token`              | Yes      | Token to deliver: `usdc` or `usdt`.        |
| `destinationAddress` | Yes      | Recipient address on the destination chain |

When `withdraw` succeeds, Ground has accepted the request and reserved liquidity against the wallet. The requested `amountUsd` remains the target amount for the withdrawal, but the payout legs are the source of truth for what was actually delivered. Integrators should set end-user expectations based on the underlying yield source, especially for asynchronous exits.

Sandbox notes:

* In sandbox, use explicit testnet keys such as `destinationChain: "ethereum_sepolia"`.
* Sandbox USDT withdrawals require `token: "usdt"` with `destinationChain: "ethereum_sepolia"`.
* `destinationAddress` must match the selected chain format: EVM hex for EVM chains, base58 for `solana`.

## List withdrawals

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X GET "$BASE_URL/v2/wallets/$WALLET_ID/withdrawals?limit=25" \
  -H "Authorization: Bearer $API_TOKEN"
```

Query parameters:

| Param          | Description                                                          |
| -------------- | -------------------------------------------------------------------- |
| `limit`        | Max items (default 50, max 200)                                      |
| `cursor`       | Opaque cursor from `nextCursor`                                      |
| `sort`         | Sort field (default `createdAt`)                                     |
| `order`        | `desc` (default) or `asc`                                            |
| `createdAtGte` | ISO-8601 timestamp filter                                            |
| `status`       | Repeatable status filter (e.g. `status=processing&status=completed`) |

## Fetch a withdrawal

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X GET "$BASE_URL/v2/wallets/$WALLET_ID/withdrawals/$WITHDRAWAL_ID" \
  -H "Authorization: Bearer $API_TOKEN"
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "0ad2fd60-f906-46fd-a395-f50b21dccd18",
  "amountRequestedUsd": "5.000000",
  "amountPaidUsd": "5.000000",
  "feeUsd": "0.000000",
  "destinationChain": "ethereum_sepolia",
  "destinationAddress": "0x76F8fc6667E239f83a547d4e16225d6a34f6FA22",
  "destinationToken": "usdc",
  "status": "completed",
  "legsCompleted": 2,
  "legsTotal": 2,
  "payoutLegs": [
    {
      "status": "completed",
      "amountUsd": "2.999999",
      "from": { "kind": "yield_source", "id": "morpho-steakhouse-usdc", "label": "Morpho Steakhouse USDC Prime" },
      "to": { "kind": "external_payout", "id": "external_payout:ethereum_sepolia:usdc", "label": "External payout (Ethereum Sepolia)" },
      "startedAt": "2026-07-09T21:37:22.227Z",
      "completedAt": "2026-07-09T21:40:43.578Z",
      "stepsCompleted": 2,
      "stepsTotal": 2,
      "steps": [
        {
          "name": "Redeeming from Morpho Steakhouse USDC Prime",
          "stepKind": "yield_source_redeem",
          "sequenceRole": "yield_redeem",
          "protocolType": "morpho",
          "stepOrdinal": 0,
          "chain": "ethereum_sepolia",
          "txKind": "yield_source_redeem",
          "state": "completed",
          "startedAt": "2026-07-09T21:38:29.885Z",
          "completedAt": "2026-07-09T21:38:29.885Z",
          "cancelledAt": null
        },
        {
          "name": "Sending payout",
          "stepKind": "external_payout_transfer",
          "sequenceRole": "external_payout_transfer",
          "protocolType": "external_payout",
          "stepOrdinal": 1,
          "chain": "ethereum_sepolia",
          "txKind": "external_payout_transfer",
          "state": "completed",
          "startedAt": "2026-07-09T21:38:31.697Z",
          "completedAt": "2026-07-09T21:40:43.578Z",
          "cancelledAt": null
        }
      ]
    },
    {
      "status": "completed",
      "amountUsd": "2.000001",
      "from": { "kind": "yield_source", "id": "syrup-usdc", "label": "Syrup USDC" },
      "to": { "kind": "external_payout", "id": "external_payout:ethereum_sepolia:usdc", "label": "External payout (Ethereum Sepolia)" },
      "startedAt": "2026-07-09T21:37:22.227Z",
      "completedAt": "2026-07-09T21:45:10.274Z",
      "stepsCompleted": 2,
      "stepsTotal": 2,
      "steps": [
        {
          "name": "Redeeming from Syrup USDC",
          "stepKind": "syrup_request_redeem",
          "sequenceRole": "yield_redeem",
          "protocolType": "syrup",
          "stepOrdinal": 0,
          "chain": "ethereum_sepolia",
          "txKind": "yield_source_redeem",
          "state": "completed",
          "startedAt": "2026-07-09T21:39:05.596Z",
          "completedAt": "2026-07-09T21:39:05.596Z",
          "cancelledAt": null
        },
        {
          "name": "Sending payout",
          "stepKind": "external_payout_transfer",
          "sequenceRole": "external_payout_transfer",
          "protocolType": "external_payout",
          "stepOrdinal": 1,
          "chain": "ethereum_sepolia",
          "txKind": "external_payout_transfer",
          "state": "completed",
          "startedAt": "2026-07-09T21:44:25.926Z",
          "completedAt": "2026-07-09T21:45:10.274Z",
          "cancelledAt": null
        }
      ]
    }
  ],
  "failureReason": null,
  "createdAt": "2026-07-09T21:37:22.227Z",
  "completedAt": "2026-07-09T21:44:37.964Z"
}
```

Top-level fields:

| Field                                     | Description                                                                                                       |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `amountRequestedUsd`                      | The requested withdrawal amount (the target).                                                                     |
| `amountPaidUsd`                           | Sum of completed payout legs; `null` until at least one leg completes.                                            |
| `feeUsd`                                  | Total fee across legs (currently always `"0.000000"`).                                                            |
| `destinationChain` / `destinationAddress` | Where funds are delivered.                                                                                        |
| `destinationToken`                        | Stablecoin delivered by the withdrawal: `usdc` or `usdt`. Older records without token metadata can return `null`. |
| `status`                                  | Withdrawal status (see [Withdrawal statuses](#withdrawal-statuses)).                                              |
| `legsCompleted` / `legsTotal`             | Progress across payout legs.                                                                                      |
| `payoutLegs[]`                            | The individual payout legs of the withdrawal (see below).                                                         |
| `failureReason`                           | Populated when `status` is `failed`.                                                                              |

The `payoutLegs` array contains the individual legs of the withdrawal. Each leg moves funds from one representation (`from`) to another (`to`) through one or more onchain `steps`:

| Field                           | Description                                                                                                                                |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `status`                        | Leg status (see complete list below)                                                                                                       |
| `amountUsd`                     | Amount routed through this leg, as a fixed-precision USD string                                                                            |
| `from` / `to`                   | `{ kind, id, label }` source and destination of the leg (e.g. `yield_source` → `external_payout`)                                          |
| `startedAt` / `completedAt`     | Leg timing                                                                                                                                 |
| `stepsCompleted` / `stepsTotal` | Progress across the leg's onchain steps                                                                                                    |
| `steps[]`                       | Per-step detail: `{ name, stepKind, sequenceRole, protocolType, stepOrdinal, chain, txKind, state, startedAt, completedAt, cancelledAt }`. |

Use `portfolio_wallet.withdrawal.payout.status_changed` for per-leg progress, including the redeem and payout-transfer steps. When a step enters `pending_customer_approval`, fetch the pending Turnkey activity and verify it before approving — see [Transaction Approvals](/docs/portfolio-wallets/transaction-approvals).

### Payout statuses

Withdrawal `payoutLegs[].status` and `payoutLegs[].steps[].state` use the workflow status set:

| Status                      | Terminal | Meaning                                                                                                                           |
| --------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `created`                   | No       | Payout leg or step has been planned but has not started.                                                                          |
| `processing`                | No       | Payout is actively being processed.                                                                                               |
| `pending_customer_approval` | No       | Awaiting customer signature. Use Ground Portal or your enabled approval integration to review and approve or reject the activity. |
| `completed`                 | Yes      | Payout delivered successfully.                                                                                                    |
| `failed`                    | Yes      | Payout failed; see `failureReason`                                                                                                |
| `cancelled`                 | Yes      | Payout was cancelled (e.g. parent withdrawal cancelled)                                                                           |

## Withdrawal statuses

Withdrawals move through five public statuses:

| Status                | Meaning                                                                      |
| --------------------- | ---------------------------------------------------------------------------- |
| `processing`          | Accepted and in progress: unwinding positions, bridging, or delivering funds |
| `partially_completed` | Terminal: some payout legs completed while others did not                    |
| `completed`           | Terminal: funds delivered to destination address                             |
| `failed`              | Terminal: withdrawal failed                                                  |
| `cancelled`           | Terminal: withdrawal was cancelled                                           |

## Timing expectations

Withdrawal time depends on which yield positions need to unwind and whether cross-chain bridging is required.

| Position                 | Typical timing      | Developer note                                                                                                                                                                                       | Customer-facing copy                                                                                                                                                                                                                                                         |
| ------------------------ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Cash (USDC)              | Instant             | No unwind needed.                                                                                                                                                                                    | This withdrawal is expected to complete right away.                                                                                                                                                                                                                          |
| Cash (USDT)              | Instant             | No unwind needed. Ethereum only.                                                                                                                                                                     | This withdrawal is expected to complete right away.                                                                                                                                                                                                                          |
| `morpho-gauntlet-usdc`   | Instant (`PT0H`)    | Synchronous ERC-4626 redeem on Ethereum. There is no normal queue-based delay.                                                                                                                       | This withdrawal is expected to complete quickly and is not normally queued.                                                                                                                                                                                                  |
| `morpho-steakhouse-usdc` | Instant (`PT0H`)    | Synchronous ERC-4626 redeem on Ethereum. There is no normal queue-based delay.                                                                                                                       | This withdrawal is expected to complete quickly and is not normally queued.                                                                                                                                                                                                  |
| `syrup-usdc`             | Up to 24h (`PT24H`) | Queue-based withdrawal. Low-liquidity periods can take longer. The payout can be processed in parts, and the final amount is based on Maple's withdrawal value when the queue processes the request. | This withdrawal is queued rather than instant. Most withdrawals are processed within 24 hours, but it can take longer in low-liquidity periods. The payout can be processed in parts, and the final amount can be lower if Maple's withdrawal value falls before processing. |

Cross-chain delivery (CCTP) adds time on top of the unwind. Withdrawal previews currently estimate this CCTP leg at about 20 minutes (`PT20M`); live settlement can vary with chain and Circle attestation conditions.

For precise per-position estimates to a specific destination, use the withdrawal preview endpoint.

## Withdrawal webhooks

Subscribe to `portfolio_wallet.withdrawal.status_changed` for real-time withdrawal tracking.

See [Webhooks](/docs/portfolio-wallets/webhooks) for registration and payload details.

***

## Bridge domains reference

A bridge domain is a hard boundary for where liquidity can come from. The withdrawal engine never crosses bridge domain boundaries.

### USDC unified (CCTP)

USDC on CCTP-supported chains forms a single `usdc:unified` domain:

* Arbitrum, Base, Ethereum, Polygon, Solana

A withdrawal to any of these chains can source USDC from any other chain in the domain (via CCTP bridging).

### USDT Ethereum

In V1, USDT withdrawals are supported only to Ethereum in production and Ethereum Sepolia in sandbox.

### How cash fits in

Within a bridge domain, **cash is always the first source of liquidity**. Only if cash is insufficient will the system unwind yield positions in the same domain.

Bridge domain IDs are always lowercase and intended to be stable, but use the withdrawal preview as the canonical source of truth for what's available.
