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

# Initiate Withdrawal

> Start a skin withdrawal for the authenticated user.

# POST /client/trading/withdraw

Initiates a withdrawal (buy) trade. AssetPay purchases the item from a marketplace supplier and delivers it to the user via Steam trade offer.

**Authentication:** Client Token (`Authorization` header)

## Request

```http theme={null}
POST https://api.assetpay.gg/client/trading/withdraw
Content-Type: application/json
Authorization: CLIENT_TOKEN

{
  "items": [
    {
      "itemId": "e5f6g7h8-i9j0-1234-abcd-ef5678901234",
      "price": 45.00
    }
  ],
  "game": "730",
  "externalId": "wd_unique_789"
}
```

### Body Parameters

| Parameter        | Type   | Required | Description                                                                                                                      |
| ---------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `items`          | array  | Yes      | Items to withdraw (min 1, max 50)                                                                                                |
| `items[].itemId` | string | Yes      | Specific listing ID from `/client/market/item` (the `id` field of a listing — a UUIDv8 for CS2, compound for Rust). 5–256 chars. |
| `items[].price`  | number | Yes      | Purchase price in USD (max \$100,000). Must equal the current price returned by `/client/market/item`.                           |
| `game`           | string | No       | `"730"` or `"252490"`. Defaults to `"730"`.                                                                                      |
| `externalId`     | string | No       | Your unique tracking ID (max 128 chars). Must be unique per trade.                                                               |

## Response

```json theme={null}
{
  "requestId": "...",
  "success": true,
  "data": {
    "id": "trade-uuid",
    "type": "withdraw",
    "source": "client",
    "status": "initiated",
    "game": "730",
    "externalId": "wd_unique_789",
    "merchantId": "merchant-uuid",
    "clientUserId": "client-uuid",
    "clientSteamID": "76561198012345678",
    "clientTradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=...",
    "items": [
      {
        "id": "e5f6g7h8-i9j0-1234-abcd-ef5678901234",
        "appid": 730,
        "tradable": true,
        "amount": 1,
        "status": "initiated",
        "offer": {
          "price": 45.00
        }
      }
    ],
    "totalPrice": 45.00,
    "createdAt": "2026-03-04T10:00:00.000Z",
    "updatedAt": "2026-03-04T10:00:00.000Z"
  }
}
```

The response is a full [Trade](/reference/types#trade) object. Each withdrawal item carries its own `status` field that mirrors the trade-level status as it progresses. On a freshly initiated withdraw the items only carry the data you submitted (`itemId`, `offer.price`) — Steam-side fields like `name`, `marketHashName`, `type`, and `iconUrl` are **omitted** until AssetPay has fetched them from the marketplace. They populate on subsequent state changes; poll `GET /client/trades/{id}` or rely on callbacks for the resolved per-item view.

## How Balance Approval Works

After this endpoint is called, AssetPay sends an `initiated` callback to your backend **before purchasing anything**. Your backend checks the user's balance, deducts it, and responds with `2xx` to approve. If the balance is insufficient, respond with `4xx` (e.g. `402 Payment Required`) to reject the trade. See the [Withdrawals guide](/guides/withdrawals#the-initiated-callback) for details.

<Warning>
  Withdrawals require your merchant account to have an active callback URL configured. Calling this endpoint without one immediately fails with `MERCHANT_NO_CALLBACK_URL` (1705).
</Warning>

## Rate Limits

| Merchant Status | Limit              |
| --------------- | ------------------ |
| Verified        | 500 requests / min |
| Unverified      | 5 requests / min   |

Shared across all clients of the same merchant.

## Errors

| Code | Key                        | When                                                   |
| ---- | -------------------------- | ------------------------------------------------------ |
| 1    | `EXTERNAL_ID_EXISTS`       | The `externalId` is already in use                     |
| 2    | `MISSING_ITEMS`            | Empty items array                                      |
| 8    | `TOO_MANY_ITEMS`           | More than 50 items                                     |
| 9    | `ITEMS_UNAVAILABLE`        | Items no longer available on market                    |
| 11   | `PRICE_CHANGED`            | Offer price changed since fetch                        |
| 12   | `MERCHANT_BALANCE_LOW`     | Your merchant balance can't cover this withdrawal      |
| 13   | `INVALID_TRADEURL`         | User's trade URL is invalid                            |
| 14   | `LISTING_NOT_FOUND`        | Marketplace listing not found                          |
| 15   | `LISTING_PRICE_INVALID`    | Listing has invalid price                              |
| 16   | `INVALID_LISTING_ID`       | Invalid listing ID format                              |
| 20   | `WITHDRAW_IN_PROGRESS`     | Another withdrawal is already processing for this user |
| 1010 | `NO_BOTS_AVAILABLE`        | No Steam bots online; retry shortly                    |
| 1011 | `FLEET_DEGRADED`           | Steam fleet degraded; retry shortly                    |
| 1601 | `INVALID_AMOUNT`           | One of the offer amounts was zero or negative          |
| 1705 | `MERCHANT_NO_CALLBACK_URL` | Merchant has no active callback URL configured         |
