Purchases
Fetch and list merchant purchases. All require Authorization: Bearer mer_live_…
(Authentication).
To create a purchase, see Buy.
Fetch a purchase
GET /api/v1/merchant/purchases/{purchaseId}curl --compressed "https://merchant-api.tradeon.market/api/v1/merchant/purchases/1a2b3c4d-5e6f-7080-91a2-b3c4d5e6f708" \
-H "Authorization: Bearer mer_live_…"200 OK:
{
"purchase_id": "1a2b3c4d-5e6f-7080-91a2-b3c4d5e6f708",
"custom_id": "order-2026-05-05-0001",
"status": "completed",
"item": {
"id": "8e42bb9c-2e11-4d40-9d51-6e5d2d4b2cf1",
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"image_url": "https://cdn.tradeon.market/items/ak47-redline-ft.png",
"exterior": "Field-Tested",
"float": 0.2451,
"delivery_type": "instant",
"estimated_delivery_minutes": 2
},
"price": 18.40,
"target_steam_id": "76561197960278073",
"trade_offer_id": "9876543210",
"trade_offer_url": "https://steamcommunity.com/tradeoffer/9876543210",
"created_at": "2026-05-05T16:00:00.000Z",
"completed_at": "2026-05-05T16:02:13.421Z",
"failure": null
}price is the top-level purchase price; item has no price field. Nullable detail
fields include item.id (for a removed catalog row), image, exterior, float, estimated
delivery time, recipient, trade-offer fields and completion time. Steam IDs remain strings.
When the purchase has failed, failure is non-null. This is a response fragment:
{
"failure": {
"code": "PROVIDER_ERROR",
"message": "Provider could not deliver the item",
"refunded_amount": 18.40
}
}Errors
| HTTP | code | When |
|---|---|---|
| 400 | MERCHANT_INVALID_STATUS | ?status= is not one of created, processing, sent_to_steam, completed, failed (GET /purchases only). |
| 404 | MERCHANT_PURCHASE_NOT_FOUND | Purchase does not exist or belongs to another merchant. |
List purchases
GET /api/v1/merchant/purchasesCursor-paginated, newest first. A custom_id lookup can return multiple attempts from
buy-by-name. Keep their individual purchase IDs and follow pagination; do not assume the
first observed attempt is the final outcome of a still-running by-name call.
Query parameters
| Name | Type | Notes |
|---|---|---|
cursor | string | Opaque, from previous next_cursor. |
limit | int | 1–200, default 50. |
status | string | Filter — one of created, processing, sent_to_steam, completed, failed. See status values. Unknown values return 400 MERCHANT_INVALID_STATUS. |
custom_id | string | Exact match. |
target_steam_id | string | Exact match. |
from / to | ISO 8601 | created_at window. |
Example
curl --compressed "https://merchant-api.tradeon.market/api/v1/merchant/purchases?status=completed&limit=2" \
-H "Authorization: Bearer mer_live_…"Each entry in purchases has the full response shape shown above. For an empty result:
{
"purchases": [],
"next_cursor": null
}Status values
completed ends delivery and failed ends that attempt; the rest are in flight.
A later Steam Trade Protection rollback can still change a completed purchase to failed.
Continue handling reversal events after delivery.
| Status | Ends delivery/attempt | Meaning |
|---|---|---|
created | Accepted, balance debited, awaiting worker pickup. | |
processing | Acquiring the item from upstream (incl. provider-top-up retries). | |
sent_to_steam | Trade offer dispatched on Steam, waiting for buyer to accept. | |
completed | ✓ | Buyer accepted and the item was delivered; a later protection rollback remains possible. |
failed | ✓ | Buyer-declined / cancelled / refunded. Inspect failure.code and failure.refunded_amount. |
failed does not itself confirm a refund. Inspect failure.refunded_amount, refund
events and the balance; a refund amount can be absent when no refund has been confirmed.
Prefer webhooks over polling and use this endpoint for reconciliation: Event Catalogue.
Failure and offer metadata
See the complete purchase failure code reference.
GET and list return the same failure.code and message. refunded_amount: 0 marks
a buyer-fault outcome with no refund; null means no refund is reported.
trade_offer_id and trade_offer_url can remain present after failure or rollback.
Null means the provider has not supplied the ID, even if an offer may have been sent.
When buy-sync observes a created purchase fail, or buy-by-name replays a failed
attempt, the 409 body keeps error and additionally returns purchase_id, custom_id,
failure, trade_offer_id, and trade_offer_url. Pre-creation errors and by-name
exhaustion without a selected final response keep the ordinary HTTP error body.