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
/api/v1/boost/plansYour boost plans, with account counts and progress.
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.
curl "https://dashboard.steamlabs.dev/api/v1/boost/plans?status=running" \
-H "Authorization: Bearer $STEAMLABS_API_KEY"{
"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.
/api/v1/boost/plans/{id}One plan, in the same shape a list row has.
Create and edit a plan
/api/v1/boost/plansCreate a plan. Always a draft holding no accounts.
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.
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. |
/api/v1/boost/plans/{id}Change a plan. Every field is optional.
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.
/api/v1/boost/plans/{id}Delete a plan and detach its accounts. Answers 204.
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
/api/v1/boost/plans/{id}/toggleThe panel's one button. Running pauses, paused resumes, completed resets and re-runs, draft starts.
/api/v1/boost/plans/{id}/startStart or resume one plan by name rather than by toggling.
/api/v1/boost/plans/{id}/pauseHold one plan. Its accounts sign out and keep every minute they earned.
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
/api/v1/boost/plans/startStart every startable plan in a list.
/api/v1/boost/plans/pausePause every running plan in a list.
/api/v1/boost/plansDelete a list of plans.
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:
{
"plans_affected": 1,
"plans_skipped": 2,
"skipped": {
"019fb42e-9a61-70d2-818a-f6a56593f3a5": "no_accounts",
"019fb430-1c22-73a4-9f0e-2b7c5d1e8a44": "running"
}
}A plan's accounts
/api/v1/boost/plans/{id}/assignmentsWho is on the plan, and how far along each one is.
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.
{
"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
/api/v1/boost/plans/{id}/assignmentsPut accounts on the plan, by id list or by filter.
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:
{ "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.
{ "task_id": null, "accounts_affected": 12480, "queued": true }One account
/api/v1/boost/assignments/{id}/startQueue one account on an otherwise untouched plan.
/api/v1/boost/assignments/{id}/retryClear a failed account's error streak and backoff, and requeue it.
/api/v1/boost/assignments/{id}/stopStop one account. It stays attached, in `stopped`, until a person starts it again.
/api/v1/boost/assignments/{id}Take one account off its plan. Answers 204.
/api/v1/boost/assignments/detachTake many accounts off their plans, by `assignment_ids`.
start and retry require an Idempotency-Key and refuse under a plan lock. stop and the two detaches do neither.
The live console
/api/v1/boost/liveThe snapshot the Boost console polls: totals, plan chips and one card per boosting account.
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.
{
"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.
/api/v1/boost/sessionsThe run history, newest first.
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.
/api/v1/boost/gamesWhat you can boost: the free-to-play catalog merged with the games your accounts own.
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
/api/v1/boost/quick-boostBoost a set of accounts on a set of games without authoring a plan first.
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.
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.
/api/v1/boost/stop-allStop everything you have boosting or queued, in one pass.
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.