> ## 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.

# Deposits

> How to process skin deposits from your users.

# Deposits

A deposit is when a user sells their skin to your platform. The user sends their item via a Steam trade offer, and you receive the value as balance.

## The Deposit Flow

<Steps>
  <Step title="Fetch inventory">
    Call `GET /client/inventory` to get the user's tradeable items with current offer prices.
  </Step>

  <Step title="User selects items">
    Display the inventory in your UI. The user picks one or more items to sell.
  </Step>

  <Step title="Initiate deposit">
    Call `POST /client/trading/deposit` with the selected items and their offer prices.
  </Step>

  <Step title="Trade offer sent">
    AssetPay sends a Steam trade offer to the user. The trade moves to `active` — sitting in the user's Steam inbox awaiting acceptance.
  </Step>

  <Step title="User accepts">
    The user accepts the trade offer in Steam. The trade moves to `hold`.
  </Step>

  <Step title="Hold period (CS2 only)">
    For CS2, Steam enforces a 7-day trade protection period. The trade stays in `hold` until it ends. Rust trades skip this step entirely and transition `active → completed` directly.
  </Step>

  <Step title="Completed">
    After the hold period (CS2) or immediately after acceptance (Rust), the trade reaches `completed`. You receive a callback and credit the user's balance.
  </Step>
</Steps>

## Single-Item Deposit

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

{
  "items": [
    { "itemId": "a1b2c3d4-...", "price": 10.75 }
  ],
  "game": "730",
  "externalId": "dep_unique_123"
}
```

## Multi-Item Deposit

You can deposit multiple items in a single trade. Pass them all in the `items` array:

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

{
  "items": [
    { "itemId": "a1b2c3d4-...", "price": 10.75 },
    { "itemId": "b2c3d4e5-...", "price": 5.20 }
  ],
  "game": "730",
  "externalId": "dep_multi_456"
}
```

For Rust items that are stackable, you can specify an `amount`:

```json theme={null}
{ "itemId": "...", "price": 0.15, "amount": 3 }
```

## Request Fields

| Field            | Type    | Required | Description                                                                             |
| ---------------- | ------- | -------- | --------------------------------------------------------------------------------------- |
| `items`          | array   | Yes      | Array of items to deposit (min 1, max 250)                                              |
| `items[].itemId` | string  | Yes      | Item ID from the inventory response                                                     |
| `items[].price`  | number  | Yes      | Offer price in USD. Must match the current offer price returned by `/client/inventory`. |
| `items[].amount` | number  | No       | Quantity for stackable items (default: 1, max: 10000)                                   |
| `game`           | string  | No       | `"730"` (CS2) or `"252490"` (Rust). Defaults to `"730"`.                                |
| `externalId`     | string  | No       | Your unique tracking ID (max 128 chars). Stored as `externalId` on the trade.           |
| `isInstant`      | boolean | No       | Whether to request instant credit (default: `true`).                                    |

## Rate Limits

Two layers apply to `/client/trading/deposit`:

* **Per-merchant tier throttle** (shared across all clients): 500 req/min verified, 5 req/min unverified.
* **Per-client guard** (scoped per merchant + client Steam ID):
  * Max **5 concurrent active deposits** (not-yet-accepted: `initiated | active`) — `TOO_MANY_ACTIVE_TRADES` (HTTP 429).
  * Max **10 deposits per 5-minute rolling window** — `RATE_LIMITED` (HTTP 429).

These guard against runaway behavior on a single user. They run before pricing/inventory fetches, so a rate-limited request fails fast and cheap.

## Response

The response contains the full trade object:

```json theme={null}
{
  "requestId": "...",
  "success": true,
  "data": {
    "id": "trade-uuid",
    "type": "deposit",
    "source": "client",
    "status": "initiated",
    "game": "730",
    "externalId": "dep_unique_123",
    "merchantId": "merchant-uuid",
    "clientUserId": "client-uuid",
    "clientSteamID": "76561198012345678",
    "clientTradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=...",
    "items": [...],
    "totalPrice": 10.75,
    "isInstant": true,
    "createdAt": "2026-03-04T10:00:00.000Z",
    "updatedAt": "2026-03-04T10:00:00.000Z"
  }
}
```

## Instant Deposits

By default, `isInstant` is `true`. When enabled, AssetPay calculates how much of the deposit value can be credited instantly based on collateral, rather than waiting for the full 7-day hold period.

When a deposit enters `hold` status, the trade object includes:

* `preCredit` - the amount credited instantly (USD)
* `pendingCredit` - the remaining amount held until the hold period ends
* `collateral` - breakdown of collateral sources

If `isInstant` is set to `false`, the entire amount waits until `completed`.

The `collateral` field in the inventory response tells you the total instant credit available for that user before they start depositing.

## External ID

The `externalId` field is your own tracking identifier. Use it to link AssetPay trades back to records in your system.

<Warning>
  External IDs must be unique per trade. Reusing an ID will result in an `EXTERNAL_ID_EXISTS` error.
</Warning>

## Balance Handling for Deposits

**When to credit:**

| Event       | Action                                                |
| ----------- | ----------------------------------------------------- |
| `hold`      | Credit `preCredit` amount (if using instant deposits) |
| `completed` | Credit `pendingCredit` (the remaining held amount)    |
| `reverted`  | Reverse any instant credit that was applied           |

**When NOT to credit:**

| Event       | Action                                                        |
| ----------- | ------------------------------------------------------------- |
| `initiated` | Just acknowledge                                              |
| `active`    | Just acknowledge — Steam offer sent, awaiting user acceptance |
| `failed`    | No credit needed                                              |
| `canceled`  | No credit needed                                              |
| `declined`  | No credit needed (user declined the offer)                    |

See the [Callbacks](/guides/callbacks) guide for full details on processing each event.
