Withdrawals
A withdrawal is when a user buys a skin from the market using their balance on your platform. AssetPay purchases the item from a marketplace supplier and delivers it to the user via Steam trade offer.The Withdrawal Flow
Initiate withdrawal
The user (or your backend) calls
POST /client/trading/withdraw with the selected item details. The trade is created with INITIATED status.AssetPay calls your backend (INITIATED callback)
Before purchasing anything, AssetPay sends an
INITIATED callback to your backend. This is where you check the user’s balance and approve or reject the trade.Your backend approves or rejects
If the user has enough balance: deduct it and respond with
200. AssetPay proceeds with the purchase. If not: respond with 4xx (e.g. 402) and the trade is cancelled.Initiating a Withdrawal
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array | Yes | Array of items to withdraw (min 1, max 50) |
items[].itemId | string | Yes | Item ID from the market response |
items[].market | number | Yes | Marketplace source (from the item’s market field) |
items[].offer.price | number | Yes | The offer price in USD (max $100,000) |
items[].offer.reference | string | Yes | The offer reference from market data |
game | string | No | "730" (CS2) or "252490" (Rust). Defaults to "730". |
externalId | string | No | Your unique tracking ID (max 128 chars) |
Response
The INITIATED Callback
This is the most important callback in the entire system. When a user initiates a withdrawal, AssetPay does not start purchasing immediately. Instead, it sends anINITIATED callback to your backend and waits for your response.
Your backend should:
- Look up the user by
trade.clientSteamIDortrade.externalClientUserId - Check if they have enough balance for
trade.totalPrice - If yes: deduct the balance and respond with HTTP
200 - If no: respond with HTTP
4xx(e.g.402) to reject
Approving a withdrawal
Just respond with200 and an empty body (or any body that isn’t a rejection). AssetPay takes that as approval and starts the purchase.
Rejecting a withdrawal
Respond with any4xx status code. 402 (Payment Required) is the recommended choice:
reason field is optional but useful for debugging. Any 4xx status (400, 402, 403, 409, etc.) is treated as a rejection.
Legacy (still supported): Respond with 200 and a rejection body like { "action": "reject" }.
Both approaches cancel the trade, mark it as FAILED, and refund your merchant wallet automatically. You’ll receive a follow-up FAILED callback.
Balance Handling for Withdrawals
| Event | What your backend should do |
|---|---|
INITIATED | Check user balance, deduct it, respond 200 to approve. Or reject. |
ACTIVE | Item purchased from supplier. Acknowledge with 200. |
HOLD | Item being delivered. Acknowledge with 200. |
COMPLETED | Delivery complete. No balance action needed. |
FAILED | Refund totalPrice to the user’s balance. |
REVERTED | Refund totalPrice to the user. Check revertedBy to see who cancelled. |
Trade Reversals
In rare cases, a completed withdrawal can be reversed. This happens when either the supplier or the user cancels the Steam trade after acceptance. The trade object includes arevertedBy field:
"SUPPLIER"- the marketplace supplier reversed the trade"USER"- the user declined or cancelled the trade offer
Per-Item Purchase Status
For multi-item withdrawals, each item in theitems array has its own purchaseStatus field:
| Status | Meaning |
|---|---|
INITIATED | Purchase not started yet |
PENDING | Being purchased from supplier |
ACTIVE | Purchased, trade offer being sent |
HOLD | Trade offer sent, waiting for acceptance |
COMPLETED | Item delivered successfully |
FAILED | Purchase failed for this item |
REVERTED | Trade was reversed for this item |