WheelmachineDocs

API reference

Every route of the API, made from its contract, openapi.yaml (OpenAPI 3.1; also as JSON), each time these pages are built.

Terminal
$ curl https://api.wheelmachine.ai/v1/me -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

The basics#

Answers marked also are given by the API on that route, though its contract does not list them yet.

Account#

The account and key this call is made with#

GET/v1/me

Any key with a machine scope.

Request
curl https://api.wheelmachine.ai/v1/me \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"
Answer 200
{
  "object": "me",
  "account": {"id": "you@example.com"},
  "key": {
    "id": "key_3f9a1c2b4d5e6f70",
    "object": "key",
    "name": "laptop",
    "scopes": ["cloud:*"],
    "projects": [],
    "shown": "ak_live_abcd…wxyz",
    "state": "active",
    "rate_per_minute": 600,
    "created_at": "2026-10-23T09:00:00Z",
    "expires_at": null,
    "last_used_at": "2026-10-23T09:29:58Z"
  },
  "standing": {"can_spend": true, "balance_usd": 42.5}
}

Answers#

What each machine ran for and cost in a month#

GET/v1/usage

Needs cloud:machines:read.

Request
curl "https://api.wheelmachine.ai/v1/usage?month=2026-10" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"
Answer 200
{
  "object": "usage",
  "month": "2026-10",
  "total_usd": 0.1312,
  "machines": [
    {
      "machine": "m_01jb2xk3n4p5q6r7s8t9v0w1x2",
      "project": "prj_01jb2xk3n4p5q6r7s8t9v0w1x2",
      "running_seconds": 5904,
      "usd": 0.1312
    }
  ]
}

Parameters#

ParameterTypeWhat it is
monthin the querystringYYYY-MM; this month when left out. Matches ^[0-9]{4}-[0-9]{2}$.
projectin the querystring

Answers#

Sign-in#

Start signing a program in through the browser#

POST/v1/login/devices

No key.

For a program on a computer with a browser (wm login): no key is needed. The answer holds device_code, which the program keeps to itself, and user_code, which the person types at verification_uri, signed in to the dashboard, and approves. The code is never carried in an address (there is no verification_uri_complete): a link with someone else's code in it is how such sign-ins are stolen. The codes last 10 minutes and are used once. Then ask for the key every interval seconds (/v1/login/devices/token).

Request
curl -X POST https://api.wheelmachine.ai/v1/login/devices \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Body (it may be left out)#

FieldTypeWhat it is
namestringWhat the key will be called, such as wm on laptop. At most 80 characters.
scopesarray of ScopeWhat the program asks for; cloud:* when left out. The person may give it less.

Answers#

  • 200 The sign-in, waiting for the person: object
  • 400 invalid_request: The request is not right
  • 403 not_open: The key does not hold the scope or project this needs
  • 429 rate_limited or limit_reached: A limit is reached; Retry-After says when to try again

The program's key, once the person approved#

POST/v1/login/devices/token

No key.

202 while the person has not decided; 201 with the new key, its secret in this answer only, once they approved - named as the program asked ("wm on laptop") and holding the scopes they allowed; 403 login_denied when they refused (or signed out since); 410 login_expired when the code ran out or was used. Asked more often than interval: 429 with Retry-After.

Request
curl -X POST https://api.wheelmachine.ai/v1/login/devices/token \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Body#

FieldTypeWhat it is
device_code requiredstring

Answers#

What a program asks, by the code the person typed#

POST/v1/login/devices/lookup

The dashboard's sign-in, not a key.

The dashboard's own, signed in. The code goes in the body, never in an address.

Request
curl -X POST https://api.wheelmachine.ai/v1/login/devices/lookup \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Body#

FieldTypeWhat it is
user_code requiredstringAs the person typed it; case, spaces and dashes do not matter.
scopesarray of ScopeApproving only - what the program is given, within what it asked for.

Answers#

Let a program in#

POST/v1/login/devices/approve

The dashboard's sign-in, not a key.

The dashboard's own, signed in. scopes narrows what the program asked for; it never widens it.

Request
curl -X POST https://api.wheelmachine.ai/v1/login/devices/approve \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Body#

FieldTypeWhat it is
user_code requiredstringAs the person typed it; case, spaces and dashes do not matter.
scopesarray of ScopeApproving only - what the program is given, within what it asked for.

Answers#

Refuse a program#

POST/v1/login/devices/deny

The dashboard's sign-in, not a key.

Request
curl -X POST https://api.wheelmachine.ai/v1/login/devices/deny \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Body#

FieldTypeWhat it is
user_code requiredstringAs the person typed it; case, spaces and dashes do not matter.
scopesarray of ScopeApproving only - what the program is given, within what it asked for.

Answers#

Sign out of the dashboard here#

DELETE/v1/session

The dashboard's sign-in, not a key.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/session \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

Where the account is signed in to the dashboard#

GET/v1/sessions

The dashboard's sign-in, not a key.

Request
curl https://api.wheelmachine.ai/v1/sessions \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

  • 200 Every sign-in that still works, this one marked current: object
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 403 forbidden: The key does not hold the scope or project this needs

Sign out of the dashboard everywhere#

DELETE/v1/sessions

The dashboard's sign-in, not a key.

Every sign-in of the account ends, this one too. Keys are not touched; revoke those on their own.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/sessions \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

Sign one browser out of the dashboard#

DELETE/v1/sessions/{session_id}

The dashboard's sign-in, not a key.

That sign-in ends, and no other; this one too when it is this one. Another account's sign-in, or one that has ended, is not found.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/sessions/ses_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
session_id requiredin the pathstringMatches ^ses_[0-9a-z]{26}$.

Answers#

Which ways of signing in are open#

GET/auth/providers

No key.

A way that is not set up yet says false, and its door sends the browser back with signin=not_set_up.

Request
curl https://api.wheelmachine.ai/auth/providers \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

  • 200 The doors: object

Continue with GitHub#

GET/auth/github/start

No key.

Sends the browser to GitHub with a state, PKCE and the scopes read:user user:email. then is a place on the dashboard to come back to (/device, /keys); anything else is dropped.

Request
curl https://api.wheelmachine.ai/auth/github/start \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
thenin the querystringWhere on the dashboard to go once signed in, such as /device.

Answers#

  • 302 : On to GitHub, or back to the dashboard with signin= saying why not

Back from GitHub#

GET/auth/github/callback

No key.

Signs the person in when the state is the one this browser set out with, in time, and GitHub verified an e-mail address of theirs; the account is found - by the GitHub account's number, else by that address - or made. Otherwise back to the dashboard with signin= one of state, cancelled, unverified, held, young, unavailable, failed.

Request
curl https://api.wheelmachine.ai/auth/github/callback \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

  • 302 : Signed in and on to the dashboard, or back to it with signin= saying why not

Continue with Google#

GET/auth/google/start

No key.

Sends the browser to Google with a state, PKCE, a nonce and the scopes openid email profile.

Request
curl https://api.wheelmachine.ai/auth/google/start \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
thenin the querystringWhere on the dashboard to go once signed in, such as /device.

Answers#

  • 302 : On to Google, or back to the dashboard with signin= saying why not

Back from Google#

GET/auth/google/callback

No key.

As GitHub's way back; the ID token must be Google's, for this application, in time, this sign-in's (nonce), with email_verified.

Request
curl https://api.wheelmachine.ai/auth/google/callback \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

  • 302 : Signed in and on to the dashboard, or back to it with signin= saying why not

Projects#

The account's projects#

GET/v1/projects

Any key with a machine scope.

Request
curl "https://api.wheelmachine.ai/v1/projects?limit=50" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
limitin the queryintegerFrom 1 to 200. Left out, it is 50.
afterin the querystringThe next of the page before.

Answers#

Make a project#

POST/v1/projects

Needs cloud:projects:write.

Needs the cloud:projects:write scope. A key limited to some projects cannot make new ones.

Request
curl -X POST https://api.wheelmachine.ai/v1/projects \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "research"}'

Parameters#

ParameterTypeWhat it is
Idempotency-Keya headerstringAny string up to 255 characters, unique per attempt. The same key with the same request within 24 hours gets the first answer again (with Idempotent-Replayed: true); with a different request it is refused. At most 255 characters.

Body#

FieldTypeWhat it is
name requiredstring1 to 80 characters.

Answers#

One project#

GET/v1/projects/{project_id}

Any key with a machine scope.

Request
curl https://api.wheelmachine.ai/v1/projects/prj_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
project_id requiredin the pathstringMatches ^prj_[0-9a-z]{26}$.

Answers#

Rename a project#

PATCH/v1/projects/{project_id}

Needs cloud:projects:write.

Request
curl -X PATCH https://api.wheelmachine.ai/v1/projects/prj_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "research-2026"}'

Parameters#

ParameterTypeWhat it is
project_id requiredin the pathstringMatches ^prj_[0-9a-z]{26}$.

Body#

FieldTypeWhat it is
name requiredstring1 to 80 characters.

Answers#

Delete an empty project#

DELETE/v1/projects/{project_id}

Needs cloud:projects:write.

A project that still holds machines is refused with 409 project_not_empty.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/projects/prj_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
project_id requiredin the pathstringMatches ^prj_[0-9a-z]{26}$.

Answers#

Keys#

The account's machine keys#

GET/v1/keys

Needs cloud:keys:write.

Keys that hold at least one cloud: scope. Secrets are never shown again after a key is made.

Request
curl https://api.wheelmachine.ai/v1/keys \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

Make a key#

POST/v1/keys

Needs cloud:keys:write.

Needs the cloud:keys:write scope. A new key can hold only scopes and projects the calling key holds, so a key can never make a stronger one. The secret is in this answer only.

Request
curl -X POST https://api.wheelmachine.ai/v1/keys \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "agent", "scopes": ["cloud:machines:read", "cloud:machines:write", "cloud:machines:exec"], "expires_at": "2026-12-31T23:59:59Z"}'
Answer 201
{
  "id": "key_8c41d07e2b9a6f13",
  "object": "key",
  "name": "agent",
  "scopes": ["cloud:machines:read", "cloud:machines:write", "cloud:machines:exec"],
  "projects": [],
  "shown": "ak_live_q7rm…h2xk",
  "state": "active",
  "rate_per_minute": 600,
  "created_at": "2026-10-23T09:31:00Z",
  "expires_at": "2026-12-31T23:59:59Z",
  "last_used_at": null,
  "secret": "ak_live_..."
}

Parameters#

ParameterTypeWhat it is
Idempotency-Keya headerstringAny string up to 255 characters, unique per attempt. The same key with the same request within 24 hours gets the first answer again (with Idempotent-Replayed: true); with a different request it is refused. At most 255 characters.

Body#

FieldTypeWhat it is
name requiredstring1 to 80 characters.
scopes requiredarray of ScopeAt least 1 item.
projectsarray of string
expires_attime
rate_per_minuteintegerFrom 1 to 6000.

Answers#

Revoke a key#

DELETE/v1/keys/{key_id}

Needs cloud:keys:write.

The key stops working within seconds, everywhere. A key can revoke itself.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/keys/key_0000000000000001 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
key_id requiredin the pathstringMatches ^key_[0-9a-f]{16}$.

Answers#

Machines#

The account's snapshots, newest first#

GET/v1/snapshots

Needs cloud:machines:read.

Needs the cloud:machines:read scope. Every snapshot taken through the API of a machine that is not deleted, in the projects this key reaches - each one a new machine can start from with from_snapshot. A deleted machine's snapshots go with it.

Request
curl https://api.wheelmachine.ai/v1/snapshots \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
limitin the queryintegerFrom 1 to 200. Left out, it is 100.

Answers#

Machines, newest first#

GET/v1/machines

Needs cloud:machines:read.

Request
curl "https://api.wheelmachine.ai/v1/machines?state=running&label=team=ml&limit=20" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
projectin the querystringOnly this project's machines.
statein the queryMachineStateOne of "starting", "running", "paused", "stopped", "archived", "recovering" or "deleted".
labelin the queryarray of stringkey=value; repeat to ask for every one of several labels.
limitin the queryintegerFrom 1 to 200. Left out, it is 50.
afterin the querystringThe next of the page before.

Answers#

Make a machine#

POST/v1/machines

Needs cloud:machines:write and cloud:gpus for a machine with a GPU, and cloud:secrets:write with a key of the whole account to give it secrets.

Answers when the machine is running (201), usually in well under a second. When no server has room just now one is started for it; if that takes longer than wait_s, the answer is 202 with the machine starting, and GET /v1/machines/{machine_id}/wait follows it.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "trainer", "cpus": 4, "labels": {"team": "ml"}, "idle_after_s": 900}'
Answer 201
{
  "id": "m_01jb2xk3n4p5q6r7s8t9v0w1x2",
  "object": "machine",
  "name": "trainer",
  "project": "prj_01jb2xk3n4p5q6r7s8t9v0w1x2",
  "state": "running",
  "gpu": null,
  "size": {"cpus": 4, "memory_gb": 8},
  "location": {"city": "Helsinki", "country": "FI"},
  "cpus": 4,
  "memory_gb": 8,
  "sleep_when_idle": true,
  "idle_after_s": 900,
  "labels": {"team": "ml"},
  "network": {
    "internet": "open",
    "allow": []
  },
  "files_sealed": true,
  "running_seconds": 0.4,
  "created_at": "2026-10-23T09:30:00Z",
  "last_used_at": "2026-10-23T09:30:00Z",
  "ready_ms": 412.6
}

Parameters#

ParameterTypeWhat it is
Idempotency-Keya headerstringAny string up to 255 characters, unique per attempt. The same key with the same request within 24 hours gets the first answer again (with Idempotent-Replayed: true); with a different request it is refused. At most 255 characters.

Body#

FieldTypeWhat it is
namestringFor people; ids are made by us. At most 80 characters.
projectstringIts project; the account's first project when left out.
regionstringA region id from GET /v1/regions to run near. Where it runs is said in location.
gpustringA GPU id from GET /v1/gpus. Needs the cloud:gpus scope. Coming Not open to every account yet: such a call answers 403 not_open.
cpusintegerIts processors, with 2 GB of memory each: 16 is sixteen processors and 32 GB. Charged by the second at the 2-processor price that many times over (16 is 8 times). Not with gpu: a GPU machine's size comes with it. One of 2, 4, 8 or 16. Left out, it is 2.
labelsobject of stringsAt most 32.
secretsarray of stringNames of the account's secrets that every command run in the machine gets as environment variables. Giving them needs the cloud:secrets:write scope too, and a key of the whole account; each must be set already. A command can read its environment: any key that may run commands in the machine can read what it was given.
networkobjectIts internet policy, the outbound gate. Left out, the machine is open - it reaches the internet as every machine always could. A machine made from a snapshot keeps the source machine's policy unless this sets its own.
from_snapshotobject
from_snapshot.machine requiredstring
from_snapshot.snapshotstringA snapshot's id; its latest when left out.
sleep_when_idlebooleanTrue: it pauses by itself once it is idle - no call or connection has reached it for idle_after_s and its programs have been quiet as long (under 5% of one CPU on average), so a job left running keeps it going. Paused, it keeps its memory and no running time is charged. False: it never pauses by itself; it runs, and is charged, until it is paused or stopped. Left out, it is true.
idle_after_sintegerHow long it must be idle before it pauses by itself. Only with sleep_when_idle true. From 60 to 86400. Left out, it is 300.
wait_snumberFrom 0 to 600. Left out, it is 60.

Answers#

  • 201 Running: a Machine
  • 202 Starting; follow it with the wait call: a Machine
  • 400 invalid_request: The request is not right
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 402 payment_required: The account cannot spend now - its limit for this month is reached, or the account is held
  • 403 forbidden or not_open: The key does not hold the scope or project this needs
  • 404 not_found: The project, or the machine in from_snapshot, is not one this key reaches
  • 409 conflict or not_open: The first call with this Idempotency-Key is still running; or its internet is held back and no server here can hold back a machine's internet yet (not_open)
  • 422 invalid_request: This Idempotency-Key was used with a different request
  • 429 rate_limited or limit_reached: A limit is reached; Retry-After says when to try again
  • 503 unavailable: No room just now; Retry-After says when to try again

One machine#

GET/v1/machines/{machine_id}

Needs cloud:machines:read.

Request
curl https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Answers#

Rename a machine, move it to another project, or change its labels, secrets or internet#

PATCH/v1/machines/{machine_id}

Needs cloud:machines:write and cloud:secrets:write with a key of the whole account to give it secrets.

Labels merge: a label given null is taken off. A machine moves only to a project this key reaches, and keeps everything of its own as it goes. Everything asked is changed at once, or nothing is. What it was made as - its size and when it sleeps by itself - stays as it was made: a new machine started from a snapshot of it can be made otherwise.

Request
curl -X PATCH https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "trainer-2", "labels": {"stage": "done", "team": null}}'

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Body#

FieldTypeWhat it is
namestringAt most 80 characters.
projectstringAnother of the account's projects to move it to, one this key reaches.
labelsobject of strings or nulls
secretsobjectEvery secret it is to get, said whole: the list takes the place of the one it had, and [] takes them all away (which needs no cloud:secrets:write: it gives nothing).
networkobjectIts internet policy, said whole: it takes the place of the one it had. A running machine has its policy changed on its host at once, without a restart.

Answers#

  • 200 The machine as it is now: a Machine
  • 400 invalid_request: The request is not right
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: The machine, or the project it is moved to, is not one this key reaches
  • 409 conflict or not_open: Its internet was held back while it runs on a server that cannot hold it back (not_open): the rule is kept, and takes effect when it next starts on a server that can

Delete a machine and its files#

DELETE/v1/machines/{machine_id}

Needs cloud:machines:write.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Answers#

Run it again, from paused, stopped or archived#

POST/v1/machines/{machine_id}/start

Needs cloud:machines:write.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/start \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"wait_s": 60}'

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Body (it may be left out)#

FieldTypeWhat it is
wait_snumberFrom 0 to 600. Left out, it is 60.

Answers#

  • 200 Running: a Machine
  • 202 Starting: a Machine
  • 400 invalid_request: wait_s is not between 0 and 600
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 402 payment_required: The account cannot spend now - its limit for this month is reached, or the account is held
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: Nothing of that id that this key can see
  • 409 conflict or not_open: The machine cannot start in the state it is in; or its internet is held back and no server here can hold back a machine's internet yet (not_open)
  • 429 rate_limited or limit_reached: Too many calls just now, or the account has as many machines running or kept as it may
  • 503 unavailable: No room just now; Retry-After says when to try again

Pause it with its memory kept#

POST/v1/machines/{machine_id}/pause

Needs cloud:machines:write.

Nothing runs and no running time is charged; start brings it back where it was.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/pause \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Answers#

Stop it; its files stay#

POST/v1/machines/{machine_id}/stop

Needs cloud:machines:write.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/stop \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Answers#

Put its files away in storage, the cheapest way to keep it#

POST/v1/machines/{machine_id}/archive

Needs cloud:machines:write.

Sealed with the account's key when the machine's files are sealed. start brings it back.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/archive \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Answers#

A new machine, a copy of this one as it is now#

POST/v1/machines/{machine_id}/copy

Needs cloud:machines:write.

Made beside the original where there is room, so the files are copied in a moment. The copy's internet is held back as the original's is: when it is and no server here can hold back a machine's internet yet, the answer is 409 not_open.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/copy \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "trainer-copy"}'

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
Idempotency-Keya headerstringAny string up to 255 characters, unique per attempt. The same key with the same request within 24 hours gets the first answer again (with Idempotent-Replayed: true); with a different request it is refused. At most 255 characters.

Body (it may be left out)#

FieldTypeWhat it is
namestringAt most 80 characters.
labelsobject of stringsAt most 32.
wait_snumberFrom 0 to 600. Left out, it is 60.

Answers#

The machine's snapshots, newest first#

GET/v1/machines/{machine_id}/snapshots

Needs cloud:machines:read.

Needs the cloud:machines:read scope. Those taken through the API; a deleted machine has none.

Request
curl https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/snapshots \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
limitin the queryintegerFrom 1 to 200. Left out, it is 100.

Answers#

Keep its files as they are now#

POST/v1/machines/{machine_id}/snapshots

Needs cloud:machines:write.

A new machine can be made from a snapshot with from_snapshot.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/snapshots \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note": "before the upgrade"}'
Answer 201
{
  "id": "20261023T093500Z-3f2a0001",
  "object": "snapshot",
  "machine": "m_01jb2xk3n4p5q6r7s8t9v0w1x2",
  "note": "before the upgrade",
  "created_at": "2026-10-23T09:35:00Z"
}

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
Idempotency-Keya headerstringAny string up to 255 characters, unique per attempt. The same key with the same request within 24 hours gets the first answer again (with Idempotent-Replayed: true); with a different request it is refused. At most 255 characters.

Body (it may be left out)#

FieldTypeWhat it is
notestringAt most 200 characters.

Answers#

Answer when the machine reaches a state#

GET/v1/machines/{machine_id}/wait

Needs cloud:machines:read.

Request
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/wait?state=running&timeout_s=120" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
state requiredin the queryMachineStateOne of "starting", "running", "paused", "stopped", "archived", "recovering" or "deleted".
timeout_sin the querynumberFrom 0 to 600. Left out, it is 60.

Answers#

What the machine used, step by step, over the last day#

GET/v1/machines/{machine_id}/metrics

Needs cloud:machines:read.

Needs the cloud:machines:read scope. Its processors as a share of its own size, the most memory it held and the most it may hold, and the bytes a second it read and wrote on its disk and received and sent on its network - a point for each step from since on. Its server reads it every few seconds while it runs and keeps a point a minute for the last day, in memory: a step it was paused or stopped through has no point, and the numbers begin again when the machine moves to another server or its server's program starts anew (kept_since says how far back they go). A machine that is not on a server just now has no points.

Request
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/metrics?since=6h&step=5m" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
sincein the querystringFrom when: a time (RFC 3339), or how long ago (90s, 15m, 6h, 1d); the last hour when left out, and at most a day back. For example "6h".
stepin the querystringHow long each point covers: whole minutes from 1 to 60, in seconds (300) or as a span (5m). Left out, it is "60". For example "60".

Answers#

  • 200 Its points, the oldest first: object
  • 400 invalid_request: The request is not right
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: Nothing of that id that this key can see
  • 501 not_open: It runs on a server that does not keep its numbers yet: none come while it runs there
  • 503 unavailable: No room just now; Retry-After says when to try again

Files and commands#

Sign a short-lived SSH certificate for a machine#

POST/v1/ssh/certificates

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope. Give a public key and a machine; get back an SSH certificate good for at most an hour, for that machine alone (its one principal is the machine's id, which is also the SSH user to connect as). Present it to the SSH server (ssh_host) to open a real SSH session - for scp, sftp and editors' remote-SSH. There is no password or bare public-key login. wm ssh-config prints the matching ~/.ssh/config block. A certificate works only while the key or the sign-in that asked for it does: revoking that key, or signing out, ends the SSH sessions it opened, and it opens no more.

Request
curl -X POST https://api.wheelmachine.ai/v1/ssh/certificates \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... you@laptop", "machine": "m_01jb2xk3n4p5q6r7s8t9v0w1x2"}'

Body#

FieldTypeWhat it is
public_key requiredstringOne line of an OpenSSH public key (ssh-ed25519 AAAA..., or ecdsa/rsa).
machine requiredstringThe machine's id; the certificate opens that machine alone.
ttl_sintegerHow long it lives, in seconds; one hour at most, and the default. From 1 to 3600.

Answers#

Whether real SSH is open here, and how to reach and trust it#

GET/v1/ssh

Any key with a machine scope.

Open when SSH certificates are signed here and the SSH server's address is set: what wm ssh-config needs to point your own ssh, scp and sftp at a machine. Public keys only.

Request
curl https://api.wheelmachine.ai/v1/ssh \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

Run a command in the machine and get what it wrote#

POST/v1/machines/{machine_id}/exec

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope. A paused machine is woken for it. Commands run as the machine's user unless root is asked for; root is inside the machine only, never on our servers.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/exec \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command": ["python3", "-c", "print(2+2)"]}'
Answer 200
{
  "exit_code": 0,
  "stdout": "4\n",
  "stderr": "",
  "duration_ms": 38.2,
  "truncated": false
}

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Body#

Give command (the words, no shell) or shell (a line for sh -lc), not both.

FieldTypeWhat it is
commandarray of string1 to 4096 items. For example ["python3", "-c", "print(2+2)"].
shellstringAt most 131072 characters. For example "ls -la | wc -l".
envobject of stringsEnvironment variables for this command, beside the machine's secrets, which it gets as variables too. Of a name in both, the one given here wins: the secret is left out of this command, and the answer does not say so. The command, its variables and the machine's secrets are at most 1 MiB together (413). At most 256.
cwdstringWhere it starts; the work folder when left out.
userstringOne of "user" or "root". Left out, it is "user".
binary_outputbooleanGive stdout as base64 in stdout_base64. Left out, it is false.

Answers#

  • 200 It ran; its exit code says how it ended: a ExecResult
  • 400 invalid_request: The request is not right
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 402 payment_required: The account cannot spend now - its limit for this month is reached, or the account is held
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: Nothing of that id that this key can see
  • 409 conflict or not_open: The machine cannot run a command in the state it is in; or its internet is held back and no server here can hold back a machine's internet yet (not_open)
  • 429 rate_limited or limit_reached: A limit is reached; Retry-After says when to try again
  • 503 unavailable: The command's result did not come back: it may or may not have run, so check before running it again
  • 504 timeout: The command ran longer than 10 minutes; it may still be running in the machine

Open an interactive terminal in the machine (WebSocket)#

GET/v1/machines/{machine_id}/terminal

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope. This route is a WebSocket upgrade, not a plain request: connect with Upgrade: websocket (version 13) and the usual Authorization: Bearer header. A paused machine is woken for it; the terminal is a login shell unless a command is given, as the machine's user unless root is asked for.

Over the socket, each message is one event. From you: a **binary** message is typed in (keystrokes, bytes as they are); a **text** message {"resize":{"cols":C,"rows":R}} sets the window. From us: a **binary** message is what the program wrote on its terminal; a final **text** message {"exit_code":N} (or {"reason":..., "message":...} when it did not end by itself) says how it ended, just before the socket closes.

A caller may ask for the protocol wm.terminal on the socket, and is answered with it; the dashboard's page does, beside its sign-in's token (wm.csrf.<token>), from its own address. Such a caller - a browser is never shown the answer to a handshake it was refused - is told a terminal that cannot open over the socket instead: it is switched, sent one text message {"reason": <the code>, "status": <the status>, "message": ...}, and closed with the code 4000 and that status (4501: not open for this machine). Any other caller is answered as below, before anything is switched.

An open terminal stays open only while its caller still may hold it. When the sign-in it was opened with ends (signed out, here or from another browser), the key is revoked or expires, or the account is held or can no longer spend, it is ended - at once, or at the latest at the next half-minute ping - and every caller is told why the same way: one text message {"reason": ..., "status": ..., "message": ...} (4401 signed out or the key revoked, 4403 the account held, 4402 it cannot spend), then a close with the code 4000 and that status.

We never log what is typed or shown. The audit records only that a terminal opened and closed.

Request
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/terminal?cols=120&rows=40" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
colsin the queryintegerFrom 1 to 4096. Left out, it is 80.
rowsin the queryintegerFrom 1 to 4096. Left out, it is 24.
userin the querystringOne of "user" or "root". Left out, it is "user".
termin the querystringThe terminal's kind, set as TERM inside (default xterm-256color). At most 64 characters.
cwdin the querystringWhere it starts, an absolute path; the work folder when left out. At most 1024 characters.
cmdin the querystringA word of the command to run; repeat for each word. Left out, a login shell opens.

Answers#

Read a file#

GET/v1/machines/{machine_id}/files

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope.

Request
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/files?path=work/results.csv" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -o results.csv

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
path requiredin the querystringInside the machine's home (home/...) or its work folder, where commands start (work/...). At most 1024 characters.

Answers#

Write a file, making the folders on the way#

PUT/v1/machines/{machine_id}/files

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope and a Content-Length.

Request
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/files?path=work/data.csv" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -T data.csv

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
path requiredin the querystringInside the machine's home (home/...) or its work folder, where commands start (work/...). At most 1024 characters.

Body#

The file's bytes as they are, with their length in Content-Length.

Answers#

Delete a file, or a folder#

DELETE/v1/machines/{machine_id}/files

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope. A folder goes only when it is empty, unless recursive is true: then everything in it goes with it. A link is taken away as itself, never what it points to. The home and the work folder themselves cannot be deleted.

Request
curl -X DELETE "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/files?path=work/old-runs&recursive=true" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
path requiredin the querystringInside the machine's home (home/...) or its work folder, where commands start (work/...). At most 1024 characters.
recursivein the querybooleanWith a folder, everything in it too. Left out, it is false.

Answers#

  • 204 Deleted, with nothing in the answer
  • 400 invalid_request: The request is not right
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 402 payment_required: The account cannot spend now - its limit for this month is reached, or the account is held
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: Nothing of that id that this key can see
  • 409 conflict or not_open: The folder is not empty and recursive is not true, it belongs to another user of the machine, or the machine cannot reach its files in the state it is in

What a folder holds#

GET/v1/machines/{machine_id}/folder

Needs cloud:machines:exec.

Needs the cloud:machines:exec scope. Its own entries, folders first and then by name, each with its kind, its size and when it last changed; at most 1,000, and truncated says when there were more. A paused machine is woken for it.

Request
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/folder?path=home/notes" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
path requiredin the querystringA folder of the machine's home (home, home/...) or of its work folder, where commands start (work, work/...). At most 1024 characters.

Answers#

  • 200 The folder: object
  • 400 invalid_request: The path is not one of the machine's home or work folder, or it names a file
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 402 payment_required: The account cannot spend now - its limit for this month is reached, or the account is held
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: Nothing of that id that this key can see
  • 409 conflict or not_open: The machine cannot reach its files in the state it is in
  • 501 not_open: The machine has no find that can say what each file is

Ports#

The machine's ports open at web addresses#

GET/v1/machines/{machine_id}/ports

Needs cloud:machines:read.

Needs the cloud:machines:read scope.

Request
curl https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/ports \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Answers#

Open a port of the machine at a web address of its own#

POST/v1/machines/{machine_id}/ports

Needs cloud:machines:write.

Needs the cloud:machines:write scope. Private unless public is true. A port that is open already is answered 200, made public or private as asked (left out, public is false). The ports the machine itself uses (5900, 6080, 7070, 9222, 9223 and 9224) cannot be opened (400), and a machine has at most 20 open (429 with the code limit_reached). Until web addresses are served, the answer is 503 with the code not_open, which waiting a moment does not change.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/ports \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"port": 8000}'

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.

Body#

FieldTypeWhat it is
port requiredintegerFrom 1 to 65535.
publicbooleanLeft out, it is false.

Answers#

Close a port's web address#

DELETE/v1/machines/{machine_id}/ports/{port}

Needs cloud:machines:write.

Needs the cloud:machines:write scope. The address answers 404 from then on, and links made for it no longer open it. Closing a port that is not open is answered 204 all the same.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/ports/8000 \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
port requiredin the pathintegerFrom 1 to 65535.

Answers#

A link that lets one browser into a private address for a while#

POST/v1/machines/{machine_id}/ports/{port}/link

Needs cloud:machines:read.

Needs the cloud:machines:read scope. The link opens once, within five minutes. The browser that opens it is given access to that one address for access_s seconds (a cookie for that address alone) and is taken to path on it; a page that only previews links does not use it up. The link is shown in this answer only, and each call makes a new one: it is not sent again once it may have reached the API. A port that is not open is answered 404; until web addresses are served, 503 with the code not_open.

Request
curl -X POST https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/ports/8000/link \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"path": "/", "access_s": 1800}'

Parameters#

ParameterTypeWhat it is
machine_id requiredin the pathstringMatches ^m_[0-9a-z]{26}$.
port requiredin the pathintegerFrom 1 to 65535.

Body (it may be left out)#

FieldTypeWhat it is
access_sintegerHow long the browser that opens the link may reach the address. From 60 to 3600. Left out, it is 1800.
pathstringWhere on the address the link lands: a path beginning with a single / (not // or /\), with no space or backslash in it; a query may follow it. At most 2048 characters. Left out, it is "/".

Answers#

Secrets#

The account's secrets, by name, and the machines that get each#

GET/v1/secrets

Needs cloud:machines:read.

Needs the cloud:machines:read scope. A secret's value is never shown again once it is set: not here, not in any other answer, not in the audit. A key limited to some projects lists only the secrets its projects' machines get, and sees only those machines.

Request
curl https://api.wheelmachine.ai/v1/secrets \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

  • 200 The secrets: object
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 403 forbidden: The key does not hold the scope or project this needs
  • 503 unavailable: Secrets are not set up on this API yet (unavailable, with a Retry-After of an hour)

Set a secret, or set it anew#

PUT/v1/secrets/{name}

Needs cloud:secrets:write.

Needs the cloud:secrets:write scope and a key of the whole account: secrets belong to the account, and a key limited to some projects cannot set, delete or give them (403). The value is sealed at once with a key of the account's own and kept only so; the machines given the secret get the new value from their next command. An account keeps at most 200 secrets.

Request
curl -X PUT https://api.wheelmachine.ai/v1/secrets/DATABASE_URL \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value": "postgres://app@db.example.com:5432/app"}'

Parameters#

ParameterTypeWhat it is
name requiredin the pathstringWritten as an environment variable's name is, which is what a machine's commands get it as. Matches ^[A-Z_][A-Z0-9_]{0,63}$. For example "DATABASE_URL".

Body#

FieldTypeWhat it is
value requiredstringThe value, up to 32 KiB of text with no NUL in it. It is never shown again. 1 to 32768 characters.
outsideobjectKeep the secret outside the machine: its value never enters the machine - not its environment (which holds only a placeholder wm_secret_<NAME>_<hex>), its files, its process memory or any answer. The outbound gate on the host, which is given the value and the machine is not, puts it into the header of requests going to one of hosts. Left out, the value reaches the machine's commands as an environment variable.
outside.hosts requiredarray of stringWhere its value may be sent (exact, or a leading *.). When the machine is not open these must also be allowed by its network policy, or the gate could never reach them. 1 to 32 items.
outside.header requiredstringThe request header its value is written into, such as Authorization. At most 64 characters.
outside.formatstringHow the value is written, with {value} exactly once; {value} (the value alone) by default. At most 256 characters.

Answers#

Delete a secret#

DELETE/v1/secrets/{name}

Needs cloud:secrets:write.

Needs the cloud:secrets:write scope and a key of the whole account. The secret is taken off every machine that was given it: one set again later under the same name goes to none of them until it is given anew.

Request
curl -X DELETE https://api.wheelmachine.ai/v1/secrets/DATABASE_URL \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Parameters#

ParameterTypeWhat it is
name requiredin the pathstringWritten as an environment variable's name is, which is what a machine's commands get it as. Matches ^[A-Z_][A-Z0-9_]{0,63}$. For example "DATABASE_URL".

Answers#

  • 204 Deleted, with nothing in the answer
  • 401 unauthorized or key_revoked or key_expired: No key, or a key that does not work
  • 403 forbidden: The key does not hold the scope or project this needs
  • 404 not_found: Nothing of that id that this key can see
  • 503 unavailable: Secrets are not set up on this API yet (unavailable, with a Retry-After of an hour)

Catalogue#

The sizes a machine without a GPU comes in, and what an hour of each costs#

GET/v1/sizes

Any key with a machine scope.

What an hour of a machine of each size running comes to - the price its running time is counted at. A paused machine runs no time.

Request
curl https://api.wheelmachine.ai/v1/sizes \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

Places a machine can be asked to run near#

GET/v1/regions

Any key with a machine scope.

The machine says where it actually runs in location.

Request
curl https://api.wheelmachine.ai/v1/regions \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"
Answer 200
{
  "object": "list",
  "data": [
    {"id": "helsinki", "city": "Helsinki", "country": "FI"},
    {"id": "mumbai", "city": "Mumbai", "country": "IN"}
  ]
}

Answers#

GPUs, where they are and what an hour costs#

GET/v1/gpus

Coming GPU machines are not open to every account yet: for_sale is false, and the list shows what is coming.

Any key with a machine scope.

Request
curl https://api.wheelmachine.ai/v1/gpus \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"

Answers#

Objects#

What the answers are made of. A list comes as {"object": "list", "data": [...], "next": ...}: give next as after to read the page after it; it is null on the last page.

Me#

FieldTypeWhat it is
object required"me"
account requiredobject
account.id requiredstring
account.namestringWith the dashboard's sign-in: the person's name, as their door gave it.
account.emailstringWith the dashboard's sign-in: the e-mail address GitHub or Google verified.
key requiredKey or nullThe key this call is made with; null for a call made with the dashboard's sign-in.
sessionobject
standing requiredStanding

Standing#

FieldTypeWhat it is
can_spend requiredbooleanFalse when the account's limit for this month is reached or the account is held.
balance_usdnumber or nullWhat is left to spend this month under the account's limit; null for an account with no money limit.
reasonstringWhy it cannot spend, in words a person reads.

Project#

FieldTypeWhat it is
id requiredstringFor example "prj_01jb2xk3n4p5q6r7s8t9v0w1x2".
object required"project"
name requiredstring
created_at requiredtime

Key#

FieldTypeWhat it is
id requiredstringFor example "key_3f9a1c2b4d5e6f70".
object required"key"
name requiredstring
scopes requiredarray of Scope
projects requiredarray of stringThe projects it is limited to; empty for every project of the account.
shown requiredstringIts first and last characters, to recognise it by. For example "ak_live_abcd…wxyz".
state requiredstringOne of "active", "revoked" or "expired".
rate_per_minuteinteger or null
created_at requiredtime
expires_attime or null
last_used_attime or null

KeyCreated#

A Key, with its secret: the only answer that ever holds it.

FieldTypeWhat it is
id requiredstringFor example "key_3f9a1c2b4d5e6f70".
object required"key"
name requiredstring
scopes requiredarray of Scope
projects requiredarray of stringThe projects it is limited to; empty for every project of the account.
shown requiredstringIts first and last characters, to recognise it by. For example "ak_live_abcd…wxyz".
state requiredstringOne of "active", "revoked" or "expired".
rate_per_minuteinteger or null
created_at requiredtime
expires_attime or null
last_used_attime or null
secret requiredstringThe key itself. Shown in this answer only.

Scope#

cloud:machines:read see machines, and the names of secrets; cloud:machines:write make, change, pause, copy and delete them; cloud:machines:exec run commands and read or write files in them; cloud:gpus make GPU machines; cloud:projects:write make and change projects; cloud:keys:write make and revoke keys; cloud:secrets:write set and delete secrets, and give them to machines; cloud:* all of these.

One of "cloud:*", "cloud:machines:read", "cloud:machines:write", "cloud:machines:exec", "cloud:gpus", "cloud:projects:write", "cloud:keys:write" or "cloud:secrets:write".

Machine#

FieldTypeWhat it is
id requiredstringFor example "m_01jb2xk3n4p5q6r7s8t9v0w1x2".
object required"machine"
name requiredstring
project requiredstring
state requiredMachineStateOne of "starting", "running", "paused", "stopped", "archived", "recovering" or "deleted".
gpuGpuRef or null
sizeobject or null
size.cpusinteger
size.memory_gbnumber
size.disk_gbnumber
locationobject or nullWhere it runs now.
location.citystring
location.countrystringISO 3166-1 alpha-2
cpusinteger or nullIts processors, with 2 GB of memory each; null for a GPU machine, whose size comes with its GPU. One of 2, 4, 8, 16 or null.
memory_gbnumber or nullIts memory; null for a GPU machine.
sleep_when_idlebooleanTrue: it pauses by itself once it is idle - no call or connection has reached it for idle_after_s and its programs have been quiet as long. False: it never pauses by itself.
idle_after_sinteger or nullHow long it must be idle before it pauses by itself; null when it never does.
labels requiredobject of strings
secretsarray of stringThe names of the secrets every command run in it gets as environment variables; never their values.
network requiredobjectA machine's internet policy - the outbound gate.
files_sealed requiredbooleanIts files in storage are sealed with the account's own key.
running_secondsnumberAll the time it has run, which is what is charged.
disk_bytesinteger
cpu_coresnumberProcessors it used, about a minute's average, when running.
memory_bytesinteger
created_at requiredtime
last_used_attime or null
ready_msnumberHow long making it ready took, when this answer made it ready (create, start, copy).

MachineState#

starting being made ready; running; paused memory kept, nothing running; stopped files kept, memory not; archived files in storage; recovering its server was lost and it is being brought back from its last moments; deleted.

One of "starting", "running", "paused", "stopped", "archived", "recovering" or "deleted".

GpuRef#

FieldTypeWhat it is
id requiredstringAn id from GET /v1/gpus.
modelstring
countinteger
memory_gbinteger

Snapshot#

FieldTypeWhat it is
id requiredstring
object required"snapshot"
machine requiredstring
notestring
created_at requiredtime

ExecResult#

FieldTypeWhat it is
exit_code requiredinteger
stdoutstring
stdout_base64string
stderr requiredstring
duration_ms requirednumber
truncated requiredbooleanTrue when the output was longer than 8 MiB and was cut there.

Region#

FieldTypeWhat it is
id requiredstringFor example "mumbai".
city requiredstring
country requiredstring

GpuList#

FieldTypeWhat it is
object required"list"
for_sale requiredbooleanFalse while GPU machines are not yet open to every account; the list shows what is coming.
data requiredarray of GpuOffer

GpuOffer#

FieldTypeWhat it is
id requiredstring
model requiredstringFor example "H100 80GB".
count requiredinteger
memory_gb requiredinteger
cpusinteger
ram_gbnumber
disk_gbnumber
locationobject
location.citystring
location.countrystring
price_per_hour_usd requirednumber
interruptiblebooleanMay be taken back at any time; cheaper for it.
available requiredboolean

Usage#

FieldTypeWhat it is
object required"usage"
month requiredstring
total_usd requirednumber
machines requiredarray of object
machines[].machine requiredstring
machines[].projectstring
machines[].running_seconds requirednumber
machines[].usd requirednumber

Problem#

FieldTypeWhat it is
type requiredstringA link to the page that explains this code.
title requiredstring
status requiredinteger
detailstring
code requiredstringOne of "invalid_request", "unauthorized", "key_revoked", "key_expired", "forbidden", "not_found", "conflict", "project_not_empty", "payment_required", "rate_limited", "limit_reached", "unavailable", "timeout", "too_large", "not_open", "internal", "login_denied" or "login_expired".
request_idstring
retry_after_snumber