Create a Box
Creates a Box in {org} from a base image or from a snapshot, and returns it with 202 Accepted. The Box is not usable yet: poll Get a Box until ssh.ready is true, or, with start: false, until state is stopped. See Following a request.
Any active member of the organization may create Boxes when the organization allows it (boxCreateAllowed in Get the caller; see Box creation approval). API keys need the write scope.
- Name. Unique among the organization's Boxes that are not deleted. Omit it to get
box-followed by 6 random hex characters. A deleted Box's name is free again as soon as its delete is accepted. - Source. Set
baseImage(defaultdefault) orsnapshotId, not both; the schema below cannot express this rule. List base images and List snapshots to create Boxes from show the choices. - Size. Omitted
vcpus,memoryMiBanddiskGiBcome from the base image, as List base images shows, or from the source Box's current size for a snapshot. - From a snapshot. The caller needs a grant on the snapshot's source Box, or the owner or admin role. The snapshot must be complete and in
{org}, and its source Box must not be deleted. The new Box keeps the source's base image, and its disk may be larger than the source's but not smaller. - Placement. Cubicle reserves the size for the Box's whole life on one healthy Node that has the base image, or, for a snapshot, on the Node that holds it; see Resources. When nothing fits, the request fails with
503 capacityand nothing is created. - Access. The caller gets a grant on the new Box.
start: falsecreates the Box stopped.
With an Idempotency-Key, repeating the request with the same body returns 200 OK with the Box the first request created, as it is now (even if it has been deleted since), and creates nothing. Idempotency keys has the rest of the rules, such as how long keys are kept. See Boxes.
AuthorizationBearer <token>A service account API key (cbk_…), used directly as the bearer token. read keys may call only GET routes.
org*stringThe organization's name or ID.
Idempotency-Key?stringMakes the request safe to retry: repeating it with the same key and body returns the first result instead of doing the work again. 1 to 200 characters; a UUID is a good choice.
1 <= length <= 200Every field is optional, and an empty body creates a running default Box with a generated name. snapshotId and baseImage are mutually exclusive.
application/json- body
name?string^[a-z0-9][a-z0-9-]{0,62}$vcpus?integer1 <= value <= 64memoryMiB?integer256 <= value <= 262144diskGiB?integer1 <= value <= 2048start?booleantruesnapshotId?stringuuidbaseImage?string"default""omarchy"An Idempotency-Key replay: the Box the first request with this key created, as it is now.
application/json- response
storage?The state of background checkpoint uploads of the Box's disk and saved memory to remote storage. Every Box response includes it. It is informational: no route restores a Box from a checkpoint.
id*stringThe Box's ID. It never changes.
baseImage*BaseImageIdThe base image the Box's disk was created from. A Box created from a snapshot has its source Box's image.
"default""omarchy"org*The organization that owns the Box.
name*stringUnique among the organization's Boxes that are not deleted: the NAME in ORG/NAME.
node*The Node (host) the Box runs on. A Box never moves to another Node.
spec*The CPU, memory and disk reserved for the Box on its Node for its whole life, also while it is stopped or hibernated. A free Box (pooled) gives its CPU and memory back while it is stopped or hibernated.
desired*What the Box was last asked to be.
observed*|The Node's latest report on the Box, or null before its first report.
state*BoxStateThe observed state when the report is fresh. pending before the Node's first report, unknown when the report is stale or the Node is unhealthy, which means neither running nor stopped, and deleted once the Node has removed a deleted Box.
"pending""unknown""deleted""absent""provisioning""starting""running""stopping""stopped""hibernating""hibernated""deleting""failed"hibernateAt*|When the Box hibernates automatically: 60 minutes after it first reported running since its latest start; see Box lifecycle. null until that report, and whenever the Box is not desired running or restartRequired is true. After a failed hibernation it stays in the past until the retry.
hibernationRetryAt*|When Cubicle tries again to hibernate the Box after a failed attempt, 30 s after the first failure and doubling up to 5 min; otherwise null.
pooled*booleanA free Box: its CPU and memory are reserved only while it runs.
expiresAt*|When a stopped or hibernated free Box is deleted unless it is started again.
restartRequired*booleanWhether the Box's host restarted while the Box was desired running. The Box stays down until a start request, which clears it; a stop also clears it.
connectionGeneration*numberAdvances with every start, stop, hibernation (automatic ones too), delete and restore, and when the Box's host restarts, but not when a failed hibernation returns the Box to running. SSH and private-network traffic reaches the Box only once it runs at the new value; see Generations.
privateIp*|The Box's IPv4 address on its Node's private subnet, reachable only over Cubicle's private network. null until the Box is first provisioned; it then stays the same for the Box's life.
console*Whether the Dashboard console can be used now.
ssh*Whether the Box is ready for commands and SSH now.
deletion*|pending from an accepted delete until the Node has removed the Box, after which listings no longer show it; otherwise null. complete appears only when an Idempotency-Key replay of a create returns a Box removed since.
"pending""complete"nullcreatedAt*stringWhen the Box was created.
curl -X POST 'https://api.cubicle.sh/v1/orgs/acme/boxes' \ -H 'Idempotency-Key: 4f1c7c1e-6a43-4d5e-9b7e-0d2f6c0e9a51' \ -H 'Content-Type: application/json' \ -d '{ "name": "job-1", "baseImage": "default", "vcpus": 2, "memoryMiB": 2048, "diskGiB": 12}'{ "storage": { "enabled": true, "status": "base", "checkpointId": null, "checkpointAt": null, "current": false, "processedBytes": 0, "totalBytes": 0, "error": null, "retryAt": null }, "id": "0f6c2a5e-3b1d-4c8e-9a7f-2d4e6b8c1a3f", "org": { "id": "6b1f3d2a-8c4e-4f7a-9b2d-1e5c7a9f3b6d", "name": "acme" }, "name": "job-1", "baseImage": "default", "node": { "id": "c3a9e1f7-5b2d-4a8c-8e6f-0d1b3c5e7a9f", "name": "node-1", "healthy": true }, "spec": { "vcpus": 2, "memoryMiB": 2048, "diskGiB": 12 }, "sourceSnapshotId": null, "desired": { "state": "running", "generation": 1 }, "observed": { "state": "running", "generation": 1, "observedAt": "2026-11-05T10:15:04.000Z", "ageSeconds": 2, "fresh": true, "error": null }, "state": "running", "hibernateAt": "2026-11-05T11:14:58.000Z", "hibernationRetryAt": null, "pooled": false, "expiresAt": null, "restartRequired": false, "connectionGeneration": 1, "privateIp": "10.20.30.17", "console": { "ready": true, "reason": null }, "ssh": { "ready": true, "reason": null }, "deletion": null, "createdAt": "2026-11-05T10:14:21.000Z"}
