Integrate
Studio API and API keys
Everything your team does in the studio app can be automated through the studio API. Access is by account only: every call is made with a signed-in session or an API key your organization issued.
Overview
- The API lives under
/api/b2b/v1and speaks JSON. - There is no anonymous access. The machine-readable API reference (an OpenAPI document) and the contract endpoints that list scopes, rate limits, error codes and deprecations are available to signed-in members and to API keys, not to the public.
- List endpoints are paged with cursors.
- Live streams are opened with a short-lived stream ticket, which is single-use and valid for 60 seconds.
API keys
Owners and Admins create API keys in the studio app. Each key has:
- a level, which sets the most it can ever do;
- scopes, which narrow the level to what your tooling needs;
- optionally, a restriction to specific groups, hosts or servers;
- optionally, an IP allow-list, so the key only works from your own addresses;
- optionally, its own rate limit, from 1 to 600 requests a minute (60 by default);
- an expiry date.
The key's secret is shown once, when it is created. A key can never do more than the member who owns it can do today: if that person's role is reduced, their keys are reduced with it.
Rotation and revocation
Rotating a key issues a successor and keeps the old key working for a grace period you choose (24 hours by default, up to 168), so you can roll the new secret out without downtime. Any key can be revoked at any time.
Keys are created, edited and rotated only from a signed-in member session. A key can never create another key.
What keys cannot reach
Some things are for people only, whatever a key's scopes: single sign-on and SCIM settings, accepting legal documents, and opening Remote Desktop or terminal sessions. Keys are not subject to the multi-factor authentication requirement, which is another reason to give each key only the scopes it needs and an IP allow-list.
Key levels
A key's scopes must fit inside its level. The levels, from most to least powerful:
| Level | API name | Scopes it can hold |
|---|---|---|
| Full access | full_access | All |
| Deploy and config | deploy_config | 36 |
| Operator | operator | 28 |
| Read-only | read_only | 20 |
| Monitoring only | monitoring_only | 2 |
The Monitoring only level is meant for dashboards and holds exactly monitoring:read and alerts:read.
Scopes
| Scope | Area | Allows | Levels |
|---|---|---|---|
hardware:read | Hardware | View hardware and capacity | Full access, Deploy and config, Operator, Read-only |
hardware:write | Hardware | Rent hardware and edit its assignment | Full access, Deploy and config |
hardware:release | Hardware | Release rented hardware | Full access |
groups:read | Fleet | View groups | Full access, Deploy and config, Operator, Read-only |
groups:write | Fleet | Create, edit and scale groups | Full access, Deploy and config |
instances:read | Fleet | View instances and their state | Full access, Deploy and config, Operator, Read-only |
instances:deploy | Fleet | Deploy and delete instances | Full access, Deploy and config |
instances:lifecycle | Fleet | Start, stop and restart instances | Full access, Deploy and config, Operator |
instances:console | Fleet | Send console commands | Full access, Deploy and config, Operator |
console:read | Fleet | Read live console output and history | Full access, Deploy and config, Operator |
games:read | Builds | View games and definitions | Full access, Deploy and config, Operator, Read-only |
games:write | Builds | Create and edit game definitions | Full access, Deploy and config |
games:ingest | Builds | Upload builds | Full access, Deploy and config |
config:read | Config | View configuration | Full access, Deploy and config, Operator, Read-only |
config:write | Config | Change configuration | Full access, Deploy and config |
backups:read | Data | List backups and their settings | Full access, Deploy and config, Operator, Read-only |
backups:write | Data | Create and restore backups | Full access, Deploy and config, Operator |
backups:download | Data | Download a backup archive | Full access |
files:read | Data | Download instance files | Full access, Deploy and config, Operator, Read-only |
files:write | Data | Upload instance files | Full access, Deploy and config |
schedules:read | Operate | View scheduled events | Full access, Deploy and config, Operator, Read-only |
schedules:write | Operate | Create and edit schedules | Full access, Deploy and config, Operator |
remote:sftp | Operate | Open an SFTP session against an instance | Full access, Deploy and config, Operator |
remote:sessions | Operate | End someone else's remote session | Full access |
monitoring:read | Observe | Read metrics | Full access, Deploy and config, Operator, Read-only, Monitoring only |
monitoring:write | Observe | Configure a telemetry push target | Full access |
alerts:read | Observe | Read alerts and silences | Full access, Deploy and config, Operator, Read-only, Monitoring only |
alerts:acknowledge | Observe | Acknowledge alerts and create silences | Full access, Deploy and config, Operator |
alerts:write | Observe | Edit contact points, routes and quiet hours | Full access, Deploy and config |
webhooks:read | Observe | View webhooks and their delivery history | Full access, Deploy and config, Operator, Read-only |
webhooks:write | Observe | Create, edit, test and replay webhooks | Full access, Deploy and config |
audit:read | Observe | Read the audit log | Full access, Operator, Read-only |
members:read | Account | View members and their roles | Full access, Operator, Read-only |
members:write | Account | Invite, edit and remove members | Full access |
org:read | Account | Read organization settings | Full access, Deploy and config, Operator, Read-only |
org:write | Account | Change organization settings | Full access |
org:export | Account | Export the organization's data | Full access |
keys:read | Account | List API keys and their usage | Full access, Deploy and config, Operator, Read-only |
keys:revoke | Account | Revoke an API key | Full access |
billing:read | Account | Read invoices and usage | Full access, Operator, Read-only |
billing:write | Account | Add credit and change billing settings | Full access |
credentials:read | Account | View stored credentials — labels and status, never a secret | Full access, Deploy and config, Operator, Read-only |
credentials:write | Account | Store studio credentials (Steam, registry, IdP) | Full access, Deploy and config |
legal:read | Account | Read legal documents and this org's acceptance history | Full access, Deploy and config, Operator, Read-only |
support:read | Account | Read support tickets and their replies | Full access, Deploy and config, Operator, Read-only |
support:write | Account | Open, reply to, close and reopen support tickets | Full access, Deploy and config, Operator |
reseller:read | Reseller | Read reseller settings, theme and domains | Full access, Deploy and config, Operator, Read-only |
reseller:write | Reseller | Change reseller branding, domains and pricing | Full access, Deploy and config |
These scopes are refused outright and can never be issued: keys:write, builds:read, builds:write, metrics:read and legal:accept.
Rate limits
Requests are counted over a rolling minute in several buckets at once, and a request must fit in all of them:
| Bucket | Requests a minute | Weighted by route |
|---|---|---|
| Before sign-in, per IP address | 60 | No |
| Per API key (the key's own limit) | 60 | Yes |
| Per signed-in member | 120 | Yes |
| Per organization, keys and members together | 1200 unless agreed otherwise | No |
In the weighted buckets, the limit is multiplied by the weight of the route being called, so light calls can be made more often than heavy ones:
| Route type | Weight | Applies to |
|---|---|---|
poll | x10 | Dashboard rollups, realtime-stats |
read | x5 | Every other GET |
write | x2 | POST/PUT/PATCH/DELETE that change configuration |
search | x1 | Full-text search |
control | x0.5 | Start, stop, restart, deploy, delete |
download | x1/3 | File and backup downloads |
upload | x1/6 | Build ingest, file upload |
stream | x1/6 | Stream-ticket minting |
Separately, no single key or member can make more than 600 requests a minute, however the calls are weighted.
A refused request answers 429 with a Retry-After header, and responses carry X-RateLimit-* headers describing the bucket.
Errors
Errors are returned as JSON problem documents in the RFC 9457 shape (type, title, status, detail), with a stable machine-readable code and a requestId. Quote the requestId in a support ticket and we can find the exact request.
An error code never changes meaning once it has shipped; a condition whose meaning changes gets a new code.
Idempotency
Send an Idempotency-Key header (up to 255 characters) on a POST and a retry of the same request is answered from the first result instead of being carried out twice. Keys are remembered for 24 hours.
- A replayed answer carries
Idempotency-Replayed: true. - The same key with a different body is refused with
422(IDEMPOTENCY_KEY_REUSED). - The same key while the first request is still running is refused with
409(IDEMPOTENCY_IN_PROGRESS).
Versioning
- The version is the path prefix. Within
v1, new response fields, optional request fields, enum values, routes and scopes can be added at any time, so clients must ignore fields they do not recognise. - A breaking change is released under a new prefix, served alongside
v1rather than replacing it. - A route that is going away keeps working and answers with
Deprecation,SunsetandLinkheaders, with at least 365 days between deprecation and sunset. A contract endpoint lists everything currently deprecated.