Skip to content
SteamLabs API

Endpoints

Hour boosting

Author boost plans, attach accounts, watch the live console, and start or stop hours from code.

Everything the Boost cluster does, over HTTP: author a plan (which games, for how long, on what schedule), attach accounts to it, start it, and watch the console that shows what is playing right now.

Two scopes cover the domain. boost.read for the listings and the live console, boost.write for everything that changes a plan or moves an account.

Your plan gates placement, not authoring

Hour boosting is the one entitlement enforced while work runs rather than when it is created. That has consequences worth knowing before you build against it.

Creating plans, editing them, attaching accounts and deleting them stay available whatever your subscription includes. Only the calls that start boosting refuse: starting or resuming a plan, resetting its progress, quick boosting, and starting or retrying a single account. Those answer 403 with code plan_limit_reached and the upgrade path attached.

Stopping is never refused. Pausing a plan, stopping an account and stop-all stay available even when your plan no longer covers boosting, because a lapsed subscription must never leave you holding accounts you cannot stop. Nothing is deleted or rewritten by a lock either: your plans, schedules and earned progress survive it, and the queue drains again the moment your plan covers boosting.

Concurrency (max_boost_concurrent, reported as plan.max_boost_concurrent on GET /api/v1/me) is not a refusal. It caps how many accounts play at once, and the queue is how that cap is respected: start as many as you like and the control plane places them as slots free up. The live console reports totals.capUsed and totals.capLimit so you can show the ceiling instead of discovering it.

List plans

GET/api/v1/boost/plans

Your boost plans, with account counts and progress.

API key required

Filter with status (repeatable: draft, running, paused, completed, archived) and search (matches the plan name). Sort with sort (created_at, updated_at, name, status, started_at) and direction.

Bash
curl "https://dashboard.steamlabs.dev/api/v1/boost/plans?status=running" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "data": [
        {
            "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
            "name": "Nightly grind",
            "status": "running",
            "game_mode": "fixed",
            "app_ids": [730],
            "games": [
                { "app_id": 730, "name": "Counter-Strike 2", "image": "https://cdn.cloudflare.steamstatic.com/steam/apps/730/header.jpg" }
            ],
            "games_per_account": 1,
            "rotate_every_minutes": null,
            "custom_game_name": null,
            "persona_state": "online",
            "target_mode": "fixed",
            "target_minutes": 6000,
            "target_min_minutes": null,
            "target_max_minutes": null,
            "max_concurrent": null,
            "stagger_seconds": 5,
            "schedule_enabled": false,
            "schedule": {},
            "schedule_summary": { "always": true, "never": false, "hours": 168 },
            "repeat_on_complete": false,
            "accounts_count": 120,
            "boosting_count": 48,
            "progress_percent": 21.4,
            "started_at": "2026-07-29T20:00:00+00:00",
            "completed_at": null,
            "created_at": "2026-07-01T09:15:00+00:00",
            "updated_at": "2026-07-30T14:02:11+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 50, "total": 1, "last_page": 1 }
}

Time is always minutes, never hours: the panel edits hours because a person is reading it, the API speaks the unit the planner counts in.

GET/api/v1/boost/plans/{id}

One plan, in the same shape a list row has.

API key required

Create and edit a plan

POST/api/v1/boost/plans

Create a plan. Always a draft holding no accounts.

API key required

A plan needs something to play: at least one entry in app_ids, or a custom_game_name (a free-text "non-Steam game" that occupies one of Steam's 32 slots). Everything else has a sensible default.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/boost/plans" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Nightly grind",
        "app_ids": [730, 570],
        "game_mode": "random",
        "games_per_account": 1,
        "target_mode": "fixed",
        "target_minutes": 6000,
        "stagger_seconds": 10,
        "schedule_enabled": true,
        "schedule": { "mon": [20, 21, 22, 23], "tue": [20, 21, 22, 23] }
      }'
Field Notes
game_mode fixed (every account plays the whole pool), random (each draws games_per_account picks), rotate (re-picked every rotate_every_minutes, minimum 5).
target_mode unlimited (runs until stopped), fixed (target_minutes), random (each account draws between target_min_minutes and target_max_minutes).
persona_state online, away, snooze, invisible or offline. Offline still accrues playtime, it just does not light up for friends.
max_concurrent A cap for this plan alone. Never raises your account's ceiling: it is a way to run one plan gently.
schedule Whole local hours per weekday, {"mon": [0..23], ...}, evaluated in your timezone. Switching schedule_enabled on with no hours selected is refused.
repeat_on_complete On completion, reset every account's progress and run again instead of parking the plan.
PATCH/api/v1/boost/plans/{id}

Change a plan. Every field is optional.

API key required

Only what you send is written, but the rules still see the plan as it will be afterwards: switching target_mode to fixed without a target_minutes is refused even though the body names only one of the two.

Editing a running plan is allowed, and the change is pushed down onto the accounts already attached to it. The response carries accounts_resynced with how many were reached. That matters: a worker plays what its assignment says, frozen at attach time, so without the resync a plan edited from CS2 to Dota would list as Dota while every account carried on playing CS2.

DELETE/api/v1/boost/plans/{id}

Delete a plan and detach its accounts. Answers 204.

API key required

The run history survives: sessions keep their rows with the plan reference nulled, so the hours those accounts earned never disappear from your totals.

Start, pause and reset

POST/api/v1/boost/plans/{id}/toggle

The panel's one button. Running pauses, paused resumes, completed resets and re-runs, draft starts.

API key required
POST/api/v1/boost/plans/{id}/start

Start or resume one plan by name rather than by toggling.

API key required
POST/api/v1/boost/plans/{id}/pause

Hold one plan. Its accounts sign out and keep every minute they earned.

API key required

All three answer with the plan record, so status tells you what happened. start is convergent: a plan that is already running answers 200 unchanged. A plan with no games or no accounts answers 422 with code plan_not_startable and a reason of no_games or no_accounts. Re-running a completed plan means resetting its progress, which is what toggle does for you.

toggle and start require an Idempotency-Key. pause does not: it only ever takes work away.

Bulk plan actions

POST/api/v1/boost/plans/start

Start every startable plan in a list.

API key required
POST/api/v1/boost/plans/pause

Pause every running plan in a list.

API key required
DELETE/api/v1/boost/plans

Delete a list of plans.

API key required

Each takes plan_ids, capped at 1,000 (bulk_limit_exceeded past that). POST /api/v1/boost/plans/start requires an Idempotency-Key header, because it starts real logins; the bulk pause and the bulk delete do not.

Plans that cannot start are skipped rather than failing the batch:

JSON
{
    "plans_affected": 1,
    "plans_skipped": 2,
    "skipped": {
        "019fb42e-9a61-70d2-818a-f6a56593f3a5": "no_accounts",
        "019fb430-1c22-73a4-9f0e-2b7c5d1e8a44": "running"
    }
}

A plan's accounts

GET/api/v1/boost/plans/{id}/assignments

Who is on the plan, and how far along each one is.

API key required

Filter with state (repeatable: pending, starting, boosting, paused, completed, error, cooldown, stopped) and search (matches username or persona name). Sort with sort (created_at, state, minutes_boosted, boost_started_at) and direction.

JSON
{
    "data": [
        {
            "id": "019fb431-77aa-7c10-b2d1-9e0f4a6c2b31",
            "plan_id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
            "account_id": "019fb2c1-4f88-70aa-9d33-1e8b7c5a2d90",
            "account": { "id": "019fb2c1-4f88-70aa-9d33-1e8b7c5a2d90", "username": "slabs_bot_01", "persona_name": "Nova", "avatar_url": null },
            "state": "boosting",
            "is_live": true,
            "app_ids": [730],
            "games": [{ "app_id": 730, "name": "Counter-Strike 2", "image": "https://cdn.cloudflare.steamstatic.com/steam/apps/730/header.jpg" }],
            "custom_game_name": null,
            "target_minutes": 6000,
            "minutes_boosted": 1284,
            "progress_percent": 21.4,
            "remaining_minutes": 4716,
            "worker_id": "worker-7",
            "error_message": null,
            "error_count": 0,
            "cooldown_until": null,
            "assigned_at": "2026-07-29T20:00:04+00:00",
            "boost_started_at": "2026-07-29T20:00:31+00:00",
            "last_heartbeat_at": "2026-07-30T15:41:52+00:00",
            "last_rotated_at": null,
            "completed_at": null,
            "created_at": "2026-07-29T19:58:00+00:00",
            "updated_at": "2026-07-30T15:41:52+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 50, "total": 1, "last_page": 1 }
}

Attach accounts

POST/api/v1/boost/plans/{id}/assignments

Put accounts on the plan, by id list or by filter.

API key required

Takes the standard account selection: account_ids for a list you name, or filters using exactly the keys GET /accounts accepts. The useful move is one copied object: list with ?boost=not_on_plan, then post the same filters here.

An account belongs to at most one plan. Accounts already spoken for are skipped, not refused, so a batch of five hundred where three are taken attaches 497:

JSON
{ "accounts_attached": 497, "accounts_skipped": 3, "queued": false }

A filter selection is unbounded, so it is resolved on the queue and answers 202. task_id is null because attaching creates no task to poll; watch the roster instead.

JSON
{ "task_id": null, "accounts_affected": 12480, "queued": true }

One account

POST/api/v1/boost/assignments/{id}/start

Queue one account on an otherwise untouched plan.

API key required
POST/api/v1/boost/assignments/{id}/retry

Clear a failed account's error streak and backoff, and requeue it.

API key required
POST/api/v1/boost/assignments/{id}/stop

Stop one account. It stays attached, in `stopped`, until a person starts it again.

API key required
DELETE/api/v1/boost/assignments/{id}

Take one account off its plan. Answers 204.

API key required
POST/api/v1/boost/assignments/detach

Take many accounts off their plans, by `assignment_ids`.

API key required

start and retry require an Idempotency-Key and refuse under a plan lock. stop and the two detaches do neither.

The live console

GET/api/v1/boost/live

The snapshot the Boost console polls: totals, plan chips and one card per boosting account.

API key required

This endpoint returns the panel's own payload verbatim, which is the one place on this API where keys are camelCase and times are epoch milliseconds. That is deliberate: one payload with one meaning means a dashboard built on it sees exactly what the console shows, rather than a re-shaped copy that drifts.

JSON
{
    "generatedAt": 1785425000000,
    "fleetReporting": true,
    "totals": {
        "boosting": 48,
        "queued": 12,
        "hoursToday": 214.5,
        "hoursTotal": 91320.2,
        "gamesInPlay": 3,
        "workersInUse": 6,
        "capUsed": 48,
        "capLimit": 100
    },
    "planChips": [{ "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5", "name": "Nightly grind", "live": 48 }],
    "cards": [],
    "overflow": 0,
    "cardCap": 48,
    "empty": null
}

The card grid is capped at cardCap with the remainder reported as overflow, and worker identity is anonymized into "Worker N" labels. workersInUse is null when the fleet is silent, which means "we cannot see", not zero. When nothing is boosting, empty.reason says why (no_plans, queued, schedule_closed, idle, paused, completed, draft) and empty.nextOpen says when a closed schedule reopens.

GET/api/v1/boost/sessions

The run history, newest first.

API key required

Paginated and in the ordinary house shape (snake_case, ISO 8601). Filter with plan_id, account_id and open. A run that is still going has open: true, no ended_at, and a seconds figure that is the last number a worker reported rather than a final total.

GET/api/v1/boost/games

What you can boost: the free-to-play catalog merged with the games your accounts own.

API key required

Filter with search (name, tag or app id) and owned. free marks a title any account can register a licence for; owned marks one at least one of your accounts already has.

Quick boost and stop everything

POST/api/v1/boost/quick-boost

Boost a set of accounts on a set of games without authoring a plan first.

API key required

A real (one-off) plan is created behind it and behaves like any other afterwards: rename it, edit it, give it a schedule. Takes app_ids, an optional target_minutes (omit it to run until stopped), and the standard account selection. Requires an Idempotency-Key header.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/boost/quick-boost" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Idempotency-Key: 7f3a9c2e-1b44-4d8a-9f01-cc2e5a9b1234" \
  -H "Content-Type: application/json" \
  -d '{ "app_ids": [730], "target_minutes": 90, "filters": { "boost": "not_on_plan" } }'

An id list answers 201 with the plan and the counts. A filter selection answers 202 with plan_id and queued: true. If every account you named was already on a plan, nothing was created and you get 422 with code accounts_already_boosting.

POST/api/v1/boost/stop-all

Stop everything you have boosting or queued, in one pass.

API key required

Queued accounts are stopped too, not just live ones: leaving them pending would have the control plane sign them straight back in. Answers {"accounts_affected": 48}, needs no Idempotency-Key, and is never refused.