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
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
{
"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 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 for details.
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).
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 |