Machines are not open yet. These pages describe Machines as they will open; until then, a create answers region_not_offered (422), “Machines are not offered in any region yet.”
The account's Machines (contracts/machines/machine-v2.json). Exec and file actions on a Machine are not offered yet. The overview covers what every operation shares: authentication, roles, errors, pagination, idempotency and If-Match.
Needs account.read, which owner, admin and member hold. A narrowed key may call it.
The account's Machines by name, except those being deleted: managed Machines and, in a personal account, its devices (kind byoc, which PUT /machines/self registers) from every region, whatever machines.open says; unavailable_regions names the regions whose Machines on the page could not be read. A device answers id, name, kind, region, byoc (with its key_state, derived from its current login key), created_at and updated_at; its byoc.hostname and byoc.device_id are answered to the device's person only, never to an Agent key. A narrowed key never reaches a Machine. An organization holds managed Machines only (contracts/machines/machine-v2.json kinds_by_account_kind), so its list never answers a byoc Machine or its fields, and its pages and cursors are those of its managed Machines alone.
Parameters
Name
In
Type
Required
Description
cursor
query
string
no
Opaque cursor tied to the original query shape. At least 1 characters.
limit
query
integer
no
The most items one page holds, 1 to 200; 50 when omitted. A page may hold fewer; read on with next_cursor until it is null. Default 50. 1 to 200.
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
Needs machines.write, which owner, admin and member hold. A narrowed key may not.
Any member creates Machines (machines.write); a public port also needs machines.public, and a narrowed key never does. The image is the reserved platform reference tonbo.dev/platform (machine-v2.schema.json $defs.platform_image_reference), which resolves nothing, is stored with repository and digest null and reads as stateready, or a public registry reference, which resolves to its canonical repository and linux/arm64 digest, stored with the reference, and reads as statepulling until a node has pulled it (state is computed, never stored; see getMachine); a registry reference is refused before anything is written, with 422 image_platform_unsupported when it has no linux/arm64 manifest and validation_error when it is not a public reference the resolver can fetch under machine-v2.json image.distribution (a malformed reference, an unknown or unavailable image, a redirected manifest or an oversized document). A name another Machine of the account holds answers 409 name_taken. The name, the HTTPS label <name>-<account> and the SSH username are then reserved for the account, and the Machine is recorded in its region, which is fixed for its life; without region it goes to the account's default creation region. A region where Machines are not offered (machines.open in contracts/regions/cells-v1.json) answers the shared 422 region_not_offered, and a shape that is not offered 422 shape_not_offered, before anything is written. The answer is 202 while the Machine is being created and 201 in every other state (machine-v2.json creation.create_status). Both carry Location, the Machine's URL, and the 202 also Retry-After, the seconds to wait before reading the Machine there again (machine-v2.json creation.poll_after_seconds), until its state is active or failed. A replay with the same Idempotency-Key answers the same Machine as it is now, so a replay of a Machine whose creation failed answers 201 with its failure; the key reused for another request answers 409 idempotency_conflict. Refusals carry the codes and statuses of contracts/machines/machine-v2.json errors.
Parameters
Name
In
Type
Required
Description
Idempotency-Key
header
string
yes
A value you choose for this one creation, 1 to 255 characters, such as a new UUID. Send a new one for each resource you create, and the same one only to retry that request after a timeout or a lost answer: the retry answers what the first request created, in its current state, and never creates a second. A key reused for a different database, stream or Machine answers 409. 1 to 255 characters.
Request body
application/json, required. Unknown fields are refused.
The fields below are the contract’s, with their types and limits; Manage Machines explains what each one does.
Field
Type
Required
Description
name
string
yes
1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
region
string
no
Matches ^[a-z]{2}(-gov)?-[a-z]+-[0-9]+$.
image
string
yes
1 to 512 characters.
command
array of string or null
no
1 to 64 items.
shape
string
yes
Matches ^[a-z]-[0-9]+$.
ports
array of object
no
At most 8 items.
ports[].port
integer
yes
1 to 65535.
ports[].access
one of "private" or "public"
yes
Default "private".
ports[].default
boolean
yes
env
object of string
no
At most 128 entries. Each key matches ^[A-Za-z_][A-Za-z0-9_]{0,127}$.
sleep_after_seconds
integer
no
Default 600. 30 to 86400.
idle_action
one of "suspend" or "release"
no
Default "suspend".
stop_grace_seconds
integer
no
Default 10. 0 to 230.
Response
Status
Answer
201
The Machine, no longer being created (a replay of a failed create carries its failure)
The Machine's ETag, "<id>.<revision>" for a managed Machine and "<id>" for a device (contracts/machines/machine-v2.json etag), opaque to clients. An update names it in If-Match, and a delete or a sleep may.
Location
201, 202
The Machine's URL, GET /v1/machines/{name}.
Retry-After
202, 403, 409, 422, 429
The seconds to wait before reading the Machine at Location again (machine-v2.json creation.poll_after_seconds).
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
The name is held by another live resource of the account, the Idempotency-Key already created another resource or one since deleted, or the resource’s current state does not allow the change. detail says which, and errors names the field.
No
Pick another name or a new Idempotency-Key, or read the resource again and act on its current state. (more)
The key or the account sent more requests than its rate allows.
After Retry-After
Wait for the seconds Retry-After names, then send the request again; spread requests out if it recurs. (more)
Retries
Send a new Idempotency-Key with each request and the same one when you send it again: a repeat answers what the first request did, and the key reused for a different request answers 409 (see Idempotency).
202, 403, 409, 422 and 429 carry Retry-After: wait that many seconds, then send the same request again.
Needs account.read, which owner, admin and member hold. A narrowed key may call it.
A Machine of the account. A device (kind byoc, in a personal account only) is served whatever machines.open says and answers its byoc facts, hostname and device_id to its person only, with its id as its ETag ("<id>"), which a delete may name in If-Match. A managed Machine's ETag is "<id>.<revision>" (contracts/machines/machine-v2.json etag), opaque to clients: an update names it in If-Match, and a delete or a sleep may, so a tag read from one Machine never matches another that later takes its name. A Machine is read whatever machines.open says, so a closure never hides it; a region this server cannot reach answers 503 region_unavailable. Its image names the canonical repository a registry image is pulled from and a state computed from the pull: pulling until a node has pulled the digest while the Machine is creating or active, ready once one has (always for the platform reference tonbo.dev/platform, which is never pulled), failed with a failure whose code is one of contracts/machines/machine-v2.json image.failures, and not_pulled on a failed or deleting Machine that no node pulled, since nothing will. While the image is not ready, a request that would wake the Machine answers 503 image_pulling, or 409 image_failed once the pull failed. status.conditions says why a Machine is not doing what it should: wake_blocked when its last wake was refused and none has succeeded since, with the reason, since and, for a crash backoff, retry_at; creation_delayed once it has been creating for longer than contracts/machines/machine-v2.json creation.alert_after_seconds; egress_blocked while its outbound access is blocked; and volume_purged when the Volume its spec names was purged (in practice after 30 days of suspension past the owners' notice), so it boots without it until the spec names another Volume or none. activation.revision is the spec revision the live activation was admitted with. Every spec change advances the Machine's revision, but ports and sleep_after_seconds apply at once, so a lower activation.revision means a sleep is needed only when image, command, shape or env changed; GET /machines/{name}/activations says how each earlier activation ended. A managed Machine names its creator in created_by.
Parameters
Name
In
Type
Required
Description
name
path
string
yes
The Machine's name. 1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
The Machine's ETag, "<id>.<revision>" for a managed Machine and "<id>" for a device (contracts/machines/machine-v2.json etag), opaque to clients. An update names it in If-Match, and a delete or a sleep may.
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
Needs machines.write, which owner, admin and member hold. A narrowed key may not.
A managed Machine only: a device answers 409 machine_kind_mismatch, whatever machines.open says. If-Match is required, because env and ports are replaced whole: the change is written only at the revision it names, so a missing one answers 428 precondition_required, a stale one 412 precondition_failed, and a concurrent change is never lost; an If-Match that is not this Machine's ETag, another Machine's that had the name included, also answers 412 precondition_failed, and so does a bare revision ("<n>"), whose detail says to upgrade @tonbo/cli to 0.9.0 or later (machine-v2.json etag.bare_revision). A Machine whose creation failed answers 409 machine_failed and does not change. A region where Machines are not offered answers 422 region_not_offered, and a shape that is not offered 422 shape_not_offered. A change to image, command, shape or env applies at the next activation; ports and sleep_after_seconds apply at once. A changed image follows the create's rule: the platform reference tonbo.dev/platform resolves nothing, and any other reference resolves to its canonical repository and linux/arm64 digest, or is refused before anything is written as the create refuses it (422 image_platform_unsupported or validation_error). Naming an image, the same one included, resolves it again and returns its state to pulling, so a failed pull is retried. Making a port public also needs machines.public. Refusals carry the codes and statuses of contracts/machines/machine-v2.json errors.
Parameters
Name
In
Type
Required
Description
name
path
string
yes
The Machine's name. 1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
If-Match
header
string
yes
The Machine's ETag as read, "<id>.<revision>" (contracts/machines/machine-v2.json etag); a Machine update is written only to that Machine at that revision. Required, because env and ports are replaced whole; a missing one answers 428 precondition_required. At most 500 characters.
Request body
application/json, required. Unknown fields are refused.
The fields below are the contract’s, with their types and limits; Manage Machines explains what each one does.
Field
Type
Required
Description
image
string
no
1 to 512 characters.
command
array of string or null
no
1 to 64 items.
shape
string
no
Matches ^[a-z]-[0-9]+$.
ports
array of object
no
At most 8 items.
ports[].port
integer
yes
1 to 65535.
ports[].access
one of "private" or "public"
yes
Default "private".
ports[].default
boolean
yes
env
object of string
no
At most 128 entries. Each key matches ^[A-Za-z_][A-Za-z0-9_]{0,127}$.
The Machine's ETag, "<id>.<revision>" for a managed Machine and "<id>" for a device (contracts/machines/machine-v2.json etag), opaque to clients. An update names it in If-Match, and a delete or a sleep may.
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
an update or a sleep names a Machine whose creation failed (state failed); the detail names its failure.code, and the Machine does not change: delete it and create it again
The name is held by another live resource of the account, the Idempotency-Key already created another resource or one since deleted, or the resource’s current state does not allow the change. detail says which, and errors names the field.
No
Pick another name or a new Idempotency-Key, or read the resource again and act on its current state. (more)
Needs machines.write, which owner, admin and member hold. A narrowed key may not.
A managed Machine stops and is purged with its database and logs; its name is free at once for the account's next Machine, while its hostnames stay reserved to the account. The answer is 202 with the Machine being deleted, after which it is absent from the API, or 204 with no body when the name's create never reached its region and only the name was released. A region where Machines are not offered answers 422 region_not_offered, and one this server cannot reach 503 region_unavailable. A device (kind byoc) is forgotten instead, whatever machines.open says (contracts/machines/machine-v2.json kinds.byoc.forget): it is hidden and leaves the per-person cap at once, and its name is free once the forget drains; the answer is 202 with the device as it was, or 204 when its region held no row for it; a 204 names the kind in X-Tonbo-Machine-Kind. Forgetting a device that is not the caller's own (an Agent key's) also needs api_keys.others (actionsdeletebyoc_requires_also), 403 otherwise. A device's key is not revoked: a device whose key is still active registers again at its next start. If-Match is optional; when sent it must be the Machine's current ETag (a device's is its id), or the answer is 412 precondition_failed and nothing is deleted, so a delete retried after the name was reused never deletes the new Machine. A name whose create never reached its region has no ETag to match.
Parameters
Name
In
Type
Required
Description
name
path
string
yes
The Machine's name. 1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
If-Match
header
string
no
The Machine's ETag as read (contracts/machines/machine-v2.json etag); when sent, the request acts only on that Machine at that revision, and otherwise answers 412 precondition_failed. At most 500 characters.
Response
Status
Answer
202
The Machine, being deleted, or the device, forgotten
204
The name was released, no Machine having been recorded under it, or the device was forgotten, its region holding no row for it
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
POST /v1/machines/{name}/sleep · CLI: tonbo machine sleep
Needs machines.write, which owner, admin and member hold. A narrowed key may not.
machine-controller applies the Machine's effective idle action (status.sleep). An asleep Machine wakes on its next connection; there is no wake operation. The answer is 202 while an activation runs, with Retry-After, the seconds to wait before reading the Machine again (machine-v2.json sleep.poll_after_seconds), until its status.power is asleep; and 200 with the Machine unchanged when there is nothing to do: it is asleep, or still being created. A Machine whose creation failed answers 409 machine_failed, and a device 409 machine_kind_mismatch, whatever machines.open says. A region where Machines are not offered answers 422 region_not_offered. If-Match is optional; when sent it must be the Machine's current ETag, or the answer is 412 precondition_failed and nothing changes.
Parameters
Name
In
Type
Required
Description
name
path
string
yes
The Machine's name. 1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
If-Match
header
string
no
The Machine's ETag as read (contracts/machines/machine-v2.json etag); when sent, the request acts only on that Machine at that revision, and otherwise answers 412 precondition_failed. At most 500 characters.
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
an update or a sleep names a Machine whose creation failed (state failed); the detail names its failure.code, and the Machine does not change: delete it and create it again
The name is held by another live resource of the account, the Idempotency-Key already created another resource or one since deleted, or the resource’s current state does not allow the change. detail says which, and errors names the field.
No
Pick another name or a new Idempotency-Key, or read the resource again and act on its current state. (more)
GET /v1/machines/{name}/activations · CLI: tonbo machine activations
Needs account.read, which owner, admin and member hold. A narrowed key may call it.
A managed Machine's activations, newest first: each boot or refused wake, with what woke it, the spec revision and shape it was admitted with, when, and its end (machine-v2.schema.json $defs.activation_end), null while it is live. An end's reason is why it ended: a refusal such as payment_required or crash_backoff, a stop such as idle_early, sleep_after, workload_exited (with the exit_code or signal) or funding_stop, or the node's. Any member reads it (account.read), whatever machines.open says; a narrowed key never does. A device answers 409 machine_kind_mismatch, and a region this server cannot reach 503 region_unavailable. The cursor is tied to the Machine, so it never pages another Machine that later takes the name.
Parameters
Name
In
Type
Required
Description
name
path
string
yes
The Machine's name. 1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
cursor
query
string
no
Opaque cursor tied to the original query shape. At least 1 characters.
limit
query
integer
no
The most items one page holds, 1 to 200; 50 when omitted. A page may hold fewer; read on with next_cursor until it is null. Default 50. 1 to 200.
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
The name is held by another live resource of the account, the Idempotency-Key already created another resource or one since deleted, or the resource’s current state does not allow the change. detail says which, and errors names the field.
No
Pick another name or a new Idempotency-Key, or read the resource again and act on its current state. (more)
GET /v1/machine-shapes · CLI: tonbo machine shapes
Needs account.read, which owner, admin and member hold. A narrowed key may call it.
Every shape of contracts/machines/shapes-v1.json, with whether a Machine may name it now and its list price for an hour at full use, and the shape a client proposes by default. Served to any member whatever machines.open says; a narrowed key never reaches it.
The key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.
No
Use a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
1 to 40 characters. Matches ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$. Never "self".
kind
one of "managed" or "byoc"
yes
region
string
yes
Matches ^[a-z]{2}(-gov)?-[a-z]+-[0-9]+$.
byoc
object
no
byoc.os
one of "darwin" or "linux"
yes
byoc.arch
one of "arm64" or "amd64"
yes
byoc.client
one of "yield"
yes
byoc.client_version
string
yes
At most 64 characters. Matches ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$.
At most 512 characters. Matches ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+/[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*(?:/[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*)*$.
image.digest
string or null
yes
Matches ^sha256:[0-9a-f]{64}$.
image.state
one of "pulling", "ready", "failed" or "not_pulled"
yes
image.failure
object or null
yes
image.failure.code
one of "image_unavailable", "image_platform_unsupported", "image_too_large" or "image_unsupported"
yes
image.failure.message
string
yes
1 to 512 characters. Matches ^[^\u0000-\u001f\u007f-\u009f]+$.
command
array of string or null
no
1 to 64 items.
shape
string
no
Matches ^[a-z]-[0-9]+$.
ports
array of object
no
At most 8 items.
ports[].port
integer
yes
1 to 65535.
ports[].access
one of "private" or "public"
yes
Default "private".
ports[].default
boolean
yes
env
object of string
no
At most 128 entries. Each key matches ^[A-Za-z_][A-Za-z0-9_]{0,127}$.
A shape of contracts/machines/shapes-v1.json shapes, whether a Machine may name it now, and its list price.
Field
Type
Required
Description
shape
string
yes
The shape's name, which a Machine's shape names. Matches ^[a-z]-[0-9]+$.
vcpus
integer
yes
The most vCPUs a Machine of this shape uses. At least 1.
memory_gib
number
yes
The most memory a Machine of this shape uses, in GiB. Greater than 0.
scratch_gib
number
yes
The most scratch disk a Machine of this shape uses, in GiB. Greater than 0.
offered
boolean
yes
Whether a Machine may name this shape now; a shape not offered answers 422 shape_not_offered.
suspendable
boolean
yes
Whether an idle Machine of this shape can suspend, keeping its memory to resume from. False while suspend is not offered, when an idle Machine is released instead.
ceiling_usd_micros_per_hour
integer
yes
The shape's list price for an hour at full use, in micros of USD: its vCPUs, memory and scratch disk at contracts/billing/machine-prices-v1.json's hourly prices. Billing charges what a Machine uses, never more than this. At least 0.