Skip to content
SteamLabs API

Concepts

Pagination and filtering

Work through large collections without pulling your whole account down the wire.

Every collection endpoint is paginated. There is no way to ask for everything at once, on purpose: accounts with hundreds of thousands of inventory items exist, and an endpoint that tried to serialise all of them would fail for the people who need it most.

The envelope

JSON
{
    "data": [
        { "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5", "username": "farm_001" },
        { "id": "019fb42e-9a7e-728d-b960-8b4c2162898c", "username": "farm_002" }
    ],
    "meta": {
        "page": 1,
        "per_page": 50,
        "total": 418,
        "last_page": 9
    }
}

Single records are returned bare, with no envelope:

JSON
{
    "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
    "username": "farm_001"
}

Paging

Parameter Default Max Notes
page 1 1-indexed
per_page 50 200 Values above the max are clamped, not rejected

Asking for per_page=5000 gives you 200 and says so in meta.per_page. Read the value back rather than assuming you got what you asked for.

Bash
curl "https://dashboard.steamlabs.dev/api/v1/accounts?page=2&per_page=200" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

Sorting

Parameter Notes
sort A field name from that endpoint's own list
direction asc or desc. Most listings default to desc

Each endpoint's page lists the fields it can sort by. Sorting by anything else returns 422, so a typo tells you rather than quietly falling back to the default.

Two listings do it differently and say so on their own page: GET /api/v1/profiles and GET /api/v1/profile-groups take the direction inside sort (?sort=-times_used) and have no direction parameter. GET /api/v1/trade-offers and GET /api/v1/trade-routing-templates spell the direction order instead of direction.

Filtering

Filters are plain query parameters. Every endpoint documents its own, but the shared conventions are:

Shape Example Meaning
Exact ?boost=boosting Equals
Multiple ?ban_status[]=vac&ban_status[]=game Any of. Repeat the parameter with []
Search ?search=farm_0 Substring match on the endpoint's searchable fields
Date range ?created_after=2026-07-01&created_before=2026-07-31 Inclusive, ISO 8601
Presence ?details_never_refreshed=true Booleans take true / false (or 1 / 0)

A filter that takes several values is an array parameter. Sending ?ban_status=vac where the endpoint expects a list is a 422, not a single-value match: the rule is array, and being told is better than being silently ignored. Two exceptions, both documented where they live: group_ids on GET /api/v1/profiles also accepts a comma-separated string, and status on GET /api/v1/boost/plans accepts a bare value as well as a list.

Filters combine with AND:

Bash
curl "https://dashboard.steamlabs.dev/api/v1/accounts?session=online&ban_status[]=vac&sort=created_at&direction=desc" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

Filter server-side wherever you can. Pulling 5,000 accounts to keep 40 of them costs 25 requests and a lot of waiting, where the filtered call costs one.

Counting without fetching

meta.total is the count of everything matching your filters, not just the current page. To count something, request per_page=1 and read meta.total:

Bash
curl "https://dashboard.steamlabs.dev/api/v1/tasks?status=failed&per_page=1" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

A note on stable paging

Paging is offset-based, so a collection that changes while you walk it can shift under you: a row inserted at the front pushes one row from page 1 onto page 2, and you would see it twice.

For collections that change constantly (tasks, inventory during a sell run), either sort by something stable such as created_at and filter by a fixed upper bound, or de-duplicate by ID as you collect.