Skip to main content
The REST API is what the CLI, the SDK, the MCP server and the dashboard call. Every endpoint shares the rules on this page. The endpoints themselves are in the sidebar.

Base URL

Request and response bodies are JSON, except on these endpoints:
  • File uploads and downloads are raw bytes (application/octet-stream): the request body of PUT /v1/machines/{id}/files and the response of GET /v1/machines/{id}/files/content.
  • Streams are server-sent events (text/event-stream): POST /v1/machines/{id}/exec with Accept: text/event-stream, and GET /v1/machines/{id}/desktop/watch.
  • WebSockets answer 101 Switching Protocols and then carry a stream, not JSON: GET /v1/machines/{id}/terminal and GET /v1/machines/{id}/vnc.
  • 204 No Content responses, such as a revoke or a delete, have no body.
Each endpoint page shows its content type. Times are RFC 3339, in UTC.

Authentication

Send an API key in the X-API-Key header, or as Authorization: Bearer. Create keys in the dashboard under API keys in the sidebar. A restricted key reaches only the endpoints its scopes allow.

Changes run as operations

Creating, starting, stopping, pausing, resuming and deleting a machine answer 202 Accepted with an operation at once. Get an operation follows it until it ends succeeded or failed. A machine runs one operation at a time.

Idempotency

Endpoints that list Idempotency-Key under Headers require one: any unique string, such as a UUID. Retrying a completed request with the same key returns its response instead of acting twice. The same key on a different request is 409 idempotency_conflict. Keys are kept for 7 days.

Confirming deletes

Deleting a machine (DELETE /v1/machines/{id}) and deleting a snapshot (DELETE /v1/snapshots/{id}) take an X-Confirm-Delete header: the ID or exact name of the machine or snapshot to delete. Any other value is 409 delete_confirmation_required, and nothing is deleted, so a mistyped ID cannot remove another machine. The same Idempotency-Key then works for the corrected request.
API keys created from the rollout on must send the header on a machine delete. Without it, the delete is 409 delete_confirmation_required, the message names the ID to send, and the machine is kept. Older keys and sign-in sessions (the dashboard, instabox login) can still leave it out. A delete by an older key without the header gets a Warning header in the response. The CLI’s rm and snapshot rm, the SDKs, the MCP server and the dashboard send the header.

Errors

Errors use the HTTP status and a JSON body whose code says what went wrong. Branch on code, never on message.
  • retryable is true when the same request can succeed later.
  • retryAfterSeconds, when present (no_capacity, rate_limited, machine_cooldown, agent sign-up quota_exceeded), is how many seconds to wait before a retry. An error response also sends it as the Retry-After header. A failed operation carries only the field, in its error.
  • docs_url links the code’s entry in Errors, which lists every code, the 402 billing codes among them, with whether to retry and what to do.
no_capacity (no host has room right now, as a 503 or a failed operation) is retryable. Wait retryAfterSeconds (60, which the 503 also sends as the Retry-After header). Then retry with exponential backoff (for example every few minutes), or try another size or template. A create whose operation failed replays that failure for the same Idempotency-Key, so retry with a new key. The CLI’s create exits 75 on no_capacity. run exits 75 with --fail-fast, and 125 without it.

Authentication errors

Each credential problem has its own code (reason repeats it), with hint saying how to fix it and docs linking here. All are HTTP 401. Older servers sent unauthenticated, api_key_expired or api_key_revoked instead. Those are credential errors too.
A key without the scope a route needs gets 403 missing_scope (older servers: insufficient_scope) with the scopes the route accepts in requiredScopes. The message names them too, such as this API key lacks the machines:delete scope this route needs, and a hint says to create a key with one.

OpenAPI

The full machine-readable description, every public endpoint included, is at https://api.instabox.sh/v1/openapi.json.

Create a machine

POST /v1/machines: template or snapshot, size, idle pause, metadata.

Get an operation

GET /v1/operations/{id}: follow a change until it succeeds or fails.

Run a command

POST /v1/machines/{id}/exec: one command, its output and exit code.

Errors

Every code, with whether to retry and what to do.