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

# Trade Lifecycle

> How trades progress through different statuses and what each status means.

# Trade Lifecycle

Every trade follows a state machine. Understanding the status transitions is critical for correctly handling callbacks and updating your users.

## Trade Statuses

| Status      | Description                                                                                                                                                                                                                                       |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `initiated` | Trade created. For deposits, the Steam offer has not been sent yet. For withdrawals, this is the approval gate — the merchant wallet has not been debited yet.                                                                                    |
| `pending`   | **Withdrawals only.** The supplier is sourcing the item / creating the purchase.                                                                                                                                                                  |
| `active`    | Steam trade offer has been sent to the user — awaiting their acceptance.                                                                                                                                                                          |
| `hold`      | User accepted and the items are in Steam's hold window (typically 7 days). Carries `offerID` and `holdEndDate`.                                                                                                                                   |
| `completed` | Trade finished successfully (hold expired with no reversal).                                                                                                                                                                                      |
| `canceled`  | Trade was canceled before completion — admin/user cancel, or a deposit offer that was auto-canceled after sitting unaccepted past its window.                                                                                                     |
| `declined`  | The end user actively declined (or let expire) the Steam trade offer. **Deposits:** no items received, no credit. **Withdrawals:** delivery didn't happen; your merchant wallet is refunded **minus a 2% buyer-decline penalty** (capped at \$9). |
| `failed`    | Trade failed at some point in the process (offer expired, merchant rejected the `initiated` callback, supplier purchase failed, error).                                                                                                           |
| `reverted`  | A previously completed trade was reversed by the upstream supplier or the end user (see `revertedBy`).                                                                                                                                            |

<Note>
  There is no `partial` status. `pending` and `active` **are** emitted on withdrawals as the supplier sources the item and the Steam offer is sent. Statuses are atomic per trade — for multi-item withdrawals, each item carries its own status field but the trade-level status is always one of the values above.
</Note>

## Deposit Status Flow

```
initiated
    │
    ├──► canceled        (canceled before offer sent)
    │
    ▼
active ──────────► failed   (offer expired / account restricted)
    │       │
    │       ├──► declined  (user declined the offer)
    │       │
    │       └──► canceled  (auto-canceled / admin or user cancel)
    │
    ▼
  hold ───────────► failed
    │
    ▼
completed
    │
    └──► reverted
```

### What triggers each transition:

* **initiated → active**: Steam trade offer **sent to the user** — sitting in their Steam inbox, awaiting acceptance
* **initiated → failed / canceled**: Bot dispatch failed or the trade was canceled before the offer left
* **active → hold**: User accepted, items received, Steam hold period started
* **active → failed**: Trade offer expired or the user's account has restrictions
* **active → declined**: User actively declined the Steam trade offer
* **active → canceled**: Offer auto-canceled after sitting unaccepted past its window, or an admin/user canceled it
* **hold → completed**: 7-day hold ended, no reversal detected
* **hold → failed**: Items reversed by Steam during the hold period
* **completed → reverted**: Trade was reversed after completion (uncommon; check `revertedBy`)

<Note>
  `active` ≠ "user accepted". `active` means **we sent the trade offer and it's sitting in the user's Steam inbox**. The user-accepted moment is `active → hold`.
</Note>

<Note>
  **Rust deposits skip the `hold` step.** Rust items don't have a 7-day Steam protection window, so a successful Rust deposit transitions `active → completed` directly.
</Note>

## Withdrawal Status Flow

```
initiated
    │
    ├──► canceled        (merchant or admin cancellation)
    │
    ├──► failed          (merchant rejected /initiated callback, or supplier failure)
    │
    ▼
pending ──────► failed   (supplier purchase failed)
    │
    ▼
active ───────► failed     (Steam offer expired / account restricted)
    │       └──► declined  (user declined the Steam offer)
    │
    ▼
  hold ───────► failed
    │       └──► reverted
    ▼
completed
    │
    └──► reverted
```

### What triggers each transition:

* **initiated → pending**: Merchant approved via the `initiated` callback; AssetPay starts sourcing the item from the supplier
* **initiated → failed**: Merchant rejected via callback (4xx response or rejection body), the merchant has no callback URL configured (`MERCHANT_NO_CALLBACK_URL`), or the supplier purchase failed
* **initiated → canceled**: Trade explicitly canceled before processing
* **pending → active**: Item sourced, **Steam trade offer sent to the user** — awaiting acceptance
* **pending → failed**: Supplier purchase could not be completed
* **active → hold**: User accepted the Steam trade offer, Steam hold period started
* **active → failed**: The Steam offer expired or the recipient's account is restricted
* **active → declined**: The end user actively declined the Steam offer (your merchant wallet is refunded)
* **hold → completed**: 7-day hold ended, no reversal detected
* **hold → failed**: Items reversed by Steam during the hold period
* **hold → reverted**: Trade was reversed by the supplier or user during the hold period (check `revertedBy`)
* **completed → reverted**: Trade was reversed after the hold completed

<Note>
  A withdrawal moves `initiated → pending → active → hold → completed`. Not every trade emits every intermediate status, so treat `pending` and `active` as progress signals and drive balance changes off `initiated` (deduct) and the terminal states.
</Note>

<Note>
  **Rust withdrawals normally skip the `hold` step.** Rust items have no 7-day reversal-protection window, so a successful Rust withdrawal usually transitions `active → completed` directly, with no `holdEndDate`. The exception is a Steam security escrow (recipient has no mobile authenticator), which surfaces as `hold`. CS2 withdrawals always go through `hold`, which carries `offerID` + `holdEndDate`.
</Note>

## The 7-Day Hold

Steam enforces a 7-day reversal window on CS2 trades. During this window, items can be clawed back. This affects how you should handle balance credits.

The `holdEndDate` field on the trade object tells you exactly when the hold expires.

**Without instant deposits:**

Don't credit any balance until `completed`. Simple and safe.

**With instant deposits (recommended):**

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

* `preCredit`: amount to credit immediately (calculated from collateral)
* `pendingCredit`: remaining amount to credit after the hold

Credit `preCredit` on `hold`, then credit `pendingCredit` on `completed`. If the trade gets `reverted`, reverse both.

Rust deposits skip the hold entirely — credit the full amount on `completed`.

## Terminal States

These statuses are final and won't change:

* **`completed`**: The trade is done. Balance has been settled. (Can still transition to `reverted` if Steam reverses the trade afterward.)
* **`canceled`**: The trade was canceled before processing started. No balance settlement.
* **`declined`**: The end user declined the trade offer. Deposits: no items received, no settlement. Withdrawals: delivery didn't happen — your merchant wallet is auto-refunded **minus a 2% buyer-decline penalty** (capped at \$9), so this refunds slightly less than `failed`.
* **`failed`**: The trade didn't go through. For withdrawals where you previously deducted the user's balance, refund it.
* **`reverted`**: The trade was reversed after being settled. Check `revertedBy` to understand who initiated it.

## The `revertedBy` Field

When a trade reaches `reverted`, the `revertedBy` field tells you who caused it:

| Value      | Meaning                                                        |
| ---------- | -------------------------------------------------------------- |
| `supplier` | The marketplace supplier reversed the trade (withdrawals only) |
| `user`     | The end user reversed the trade                                |

For deposits, reversals typically happen when Steam reverses the trade post-completion — `revertedBy` is set to `user` in that case. For withdrawals, either party can reverse after acceptance.

## Bot Info

During certain stages, the trade object includes `botInfo` with details about the Steam bot handling the trade:

```json theme={null}
{
  "botInfo": {
    "name": "AssetPay Bot #3",
    "avatar": "https://...",
    "steamId": "76561198...",
    "joined": "2024-01-15T00:00:00.000Z"
  }
}
```

You can show this in your UI so users know which bot to expect the trade offer from.

## Recommended UI Mapping

You probably don't want to expose all internal statuses to your users. Here's a suggested mapping:

| Internal Status | User-facing Label | Description to Show                            |
| --------------- | ----------------- | ---------------------------------------------- |
| `initiated`     | Processing        | Your trade is being set up                     |
| `pending`       | Processing        | Sourcing your item                             |
| `active`        | In Progress       | Trade offer sent, waiting for you to accept it |
| `hold`          | Held (7 days)     | Item held for Steam's protection period        |
| `completed`     | Completed         | Trade finished                                 |
| `canceled`      | Cancelled         | Trade was cancelled before processing          |
| `declined`      | Declined          | You declined the trade offer                   |
| `failed`        | Failed            | Trade didn't go through                        |
| `reverted`      | Reversed          | Trade was reversed                             |
