Appearance
Catalogue Events
GET /api/v1/merchant/purchase/events
Keep a downloaded catalogue current instead of re-downloading it: ask only for what changed since a point in time.
Download Available Items once and keep its last_update_at. Ask this endpoint for changes after it, apply them, and remember next for the next call.
Request
Headers
| Header | Required | Description |
|---|---|---|
X-Api-Key | ✅ | Your merchant API key |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
since | string | ✅ | RFC 3339 time to read after. First call: your catalogue's last_update_at. Then: the next from your previous response |
game | string | — | Comma-separated game codes (csgo, rust, dota2, tf2) to receive. Omit for all |
extended | boolean | — | Include class_id, instance_id, asset_id, bot_steam_id, float, paint_seed, inspect_url, phase on upsert cards |
limit | integer | — | Events per page, 1–50000 (default 10000) |
bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/events?since=2026-08-21T14:00:00Z&game=csgo&extended=true" \
-H "X-Api-Key: your-api-key" \
--compressedResponse
json
{
"success": true,
"message": "Successfully retrieved catalogue events",
"data": {
"since": "2026-08-21T14:00:00Z",
"next": "2026-08-21T14:00:12.512434831Z",
"count": 2,
"more": false,
"reset": false,
"events": [
{
"type": "upsert",
"at": "2026-08-21T14:00:11.004Z",
"game": "csgo",
"id": "38029384123",
"item": {
"id": "38029384123",
"name": "AK-47 | Redline (Field-Tested)",
"price": 12.45,
"image_url": "https://steamcommunity-a.akamaihd.net/economy/image/class/730/..."
}
},
{ "type": "remove", "at": "2026-08-21T14:00:12.512434831Z", "game": "csgo", "id": "38029111999" }
]
}
}| Field | Type | Description |
|---|---|---|
next | string | Pass as since next time. Nanosecond precision — send it back exactly |
count | integer | Events in this page |
more | boolean | true: the page filled up; ask again at once with the new next |
reset | boolean | true: download the catalogue again (see below); events is empty |
events[].type | string | upsert or remove |
events[].at | string | When it happened (RFC 3339, nanoseconds) |
events[].game | string | Game code |
events[].id | string | Catalogue item id — the one you pass to Create Purchase |
events[].item | object | On upsert only: the full card, same shape as an Available Items full item |
Applying changes
upsert— insert theid, or replace it if you already have it. The card is the complete current state.remove— take theidout.
Re-applying an event is safe.
Reset
The journal keeps about one hour. You get reset: true with an empty events when since is older than that, or the catalogue changed too much to stream event by event. Either way: download Available Items again and resume from the new last_update_at. A reset always arrives on its own — never mixed with changes.
Stream instead of poll
Open a Catalogue WebSocket and we stream the same events to you live. Keep this endpoint too — it is how you catch up on connect and after a gap.
Errors
| Status | Message | Cause |
|---|---|---|
400 | since must be an RFC 3339 time… | since missing or malformed |
400 | limit must be between 1 and 50000 | limit out of range |
400 | unknown game "…" | game carries a code other than csgo, rust, dota2, tf2 |
401 | invalid API key | Missing or invalid X-Api-Key |
503 | catalogue events are temporarily unavailable, retry | Journal read failed — wait for Retry-After and repeat |
