Skip to content

API reference

The public REST API is available at api.collimate.ai. All requests and responses are JSON.

  • Base URL: https://api.collimate.ai
  • Auth: Authorization: Bearer col_<tier>_<id>_<secret> on every endpoint except GET /v1/health. See Authentication.
  • Content type: application/json
  • Machine spec: openapi.yaml
MethodPathDescription
GET/v1/healthLiveness + version. Unauth.
GET/v1/imagesThe image catalog your key can address.
GET/v1/templatesAlias of /v1/images (same handler, same body).
POST/v1/templatesBake your own image into a template (Pro).
GET/v1/templates/{id}Bake phase + readiness for one template.
DELETE/v1/templates/{id}Delete a template you created.
POST/v1/templates/{id}/expectDeclare the width of your next session (Pro).
POST/v1/templates/{id}/releaseEnd the session; relax capacity now (Pro).
POST/v1/sandboxesCreate a sandbox (fork a template).
GET/v1/sandboxesList your tenant's sandboxes.
GET/v1/sandboxes/{id}One sandbox's info.
POST/v1/sandboxes/{id}/execRun a command in a sandbox.
POST/v1/sandboxes/{id}/forkLive-fork a running sandbox into N children.
POST/v1/sandboxes/{id}/connect-urlMint a scoped URL to a guest port (Pro).
GET/v1/sandboxes/{id}/connectWebSocket tunnel to a guest port (the minted URL).
POST/v1/sandboxes/{id}/suspendSuspend to disk (stops the meter).
POST/v1/sandboxes/{id}/resumeResume a suspended sandbox.
DELETE/v1/sandboxes/{id}Destroy a sandbox.
GET/v1/usageAggregated usage for your tenant.

Liveness and version. No authentication required.

{ "status": "ok", "version": "1.4.2" }

version is the API build stamp.


The image catalog: everything your key can create sandboxes from — the shared public catalog plus templates your tenant baked. GET /v1/templates is a working alias (same handler, same body); the list is wrapped in a templates object on the wire.

{
"templates": [
{ "id": "python", "name": "python", "visibility": "public",
"tier": "demo", "description": "Python 3, ready to run" }
]
}
FieldTypeDescription
idstringId to pass as template on create.
namestringDisplay name.
descriptionstringWhat the image is / what's preloaded.
visibilitystringpublic (shared catalog) or private (yours).
tierstringThe plan tier the image runs on, when applicable.

On the managed cloud only python ships today; more runtimes are on the roadmap, and bring-your-own images are a Pro capability (see Templates).


POST /v1/templates · GET /v1/templates/{id} · DELETE /v1/templates/{id}

Section titled “POST /v1/templates · GET /v1/templates/{id} · DELETE /v1/templates/{id}”

Bring your own image (Pro): POST /v1/templates bakes an OCI image into a ready-state template. Body: { "name", "image", "ready"?, "width"?, "expected_width"? }width is the fan-out you expect (a hint, not a knob), expected_width pre-warms for your first rollout, and ready declares the ready-state check ({cmd?, http?, http_timeout_s?, ports?, env?, network?}). Idempotent — safe to retry.

GET /v1/templates/{id} returns the bake phase (Pending → Converting → Distributing → Live) and readiness telemetry; DELETE /v1/templates/{id} removes a template you created (403 forbidden for shared catalog rows, 409 template_in_use while sandboxes still run on it).

See Templates and the Pro quickstart for the SDK flow (Template.bake, client.env).


POST /v1/templates/{id}/expect · .../release

Section titled “POST /v1/templates/{id}/expect · .../release”

The explicit session lifecycle (Pro): expect declares the width your next rollout session will fan out — body { "width": 512 } — so capacity is ready before the burst lands; release ends the session so capacity relaxes immediately instead of decaying. Both are optional (the platform also learns from observed demand), idempotent, and only valid on templates you created. The SDK wraps the pair as client.env(ref, width=N) — a context manager that releases on exit.


Create a sandbox by forking a template. Alias: POST /v1/sessions.

RequestCreateSandboxRequest:

{
"template": "python",
"label": "grpo-step-14",
"labels": { "run": "grpo-step-14" },
"egress": { "allow": ["pypi.org"] }
}
FieldTypeRequiredDescription
templatestringyesTemplate to fork.
labelstringnoConvenience single label.
labelsobjectnoArbitrary string labels.
egressobjectnoPer-sandbox egress policy.

Response 201CreateSandboxResponse:

{
"id": "sbx_9f2a1c7b3e40",
"template": "python",
"state": "running",
"fork_time_ms": 2.4,
"create_time_ms": 3.1,
"endpoints": {}
}

fork_time_ms/create_time_ms are per-call measurements, not guarantees; see the published benchmarks for the distribution.

endpoints maps each exposed guest port to a connect hint ("<port>": "<hint>") — not a raw dialable host address. Turn one into a usable URL with POST …/connect-url or the SDK's connect_url / cdp_url / port_forward. Empty unless the template exposes ports.

Status: 201 created · 400 bad_request · 401 unauthorized · 403 forbidden · 404 unknown template · 429 rate_limited / quota_exceeded · 503 at_capacity (retry with backoff).


GET /v1/sandboxes · GET /v1/sandboxes/{id}

Section titled “GET /v1/sandboxes · GET /v1/sandboxes/{id}”

GET /v1/sandboxes lists your tenant's sandboxes, wrapped in a sandboxes object:

{
"sandboxes": [
{ "id": "sbx_9f2a1c7b3e40", "template": "python", "state": "running" }
]
}

GET /v1/sandboxes/{id} returns a single SandboxInfo:

{
"id": "sbx_9f2a1c7b3e40",
"template": "python",
"state": "running",
"age_secs": 42.5,
"idle_secs": 1.2,
"exec_count": 7,
"labels": { "run": "grpo-step-14" },
"endpoints": {}
}

404 not_found if the sandbox doesn't exist or isn't yours. endpoints is the same per-exposed-port connect-hint map as on create — resolve a port via connect-url.


Run a command in an existing sandbox. Execs are serialized within a sandbox; files and processes persist between calls.

RequestExecRequest (see Running code for the full field table):

{
"files": [{ "path": "solve.py", "content": "print(6 * 7)" }],
"command": "python3 solve.py",
"timeout_seconds": 30,
"seed": "c0ffee…"
}

Response 200ExecResponse:

{
"id": "sbx_9f2a1c7b3e40",
"stdout": "42\n",
"stderr": "",
"exit_code": 0,
"fork_time_ms": 0.0,
"exec_time_ms": 9.7,
"total_time_ms": 10.2,
"seed": "c0ffee…",
"seed_ack": "verified"
}

Status: 200 · 400 bad_request · 404 not_found · 409 busy (in-flight exec) · 413 payload too large · 429.


Live-fork a running sandbox into count copy-on-write children that keep the parent's process memory. The parent stays running.

RequestForkRequest:

{ "count": 8, "labels": ["branch-a", "branch-b"] }
FieldTypeDescription
countintegerChildren to fork (default 1, bounded per request).
labelsstring[]Optional per-child labels.

Response 200ForkResponse:

{
"parent": "sbx_9f2a1c7b3e40",
"children": [
{ "id": "sbx_1a4f8c", "endpoints": {} },
{ "id": "sbx_2b5e9d", "endpoints": {} }
]
}

Status: 200 · 404 not_found · 409 busy (parent has an in-flight exec) · 503 at_capacity (retry with backoff).

Each child's endpoints is the same connect-hint map as on create — resolve a port with connect-url.


Mint a scoped, time-boxed URL to a port inside a running sandbox — the connect-from-outside primitive for driving an interactive in-guest service (a browser, a preview server, a notebook kernel, an OpenEnv env-server) from your own client code. Pro/Enterprise only — a Demo key gets 403 demo_tier_limit.

RequestConnectUrlRequest:

{ "port": 9222, "ttl_seconds": 600, "protocol": "cdp" }
FieldTypeRequiredDescription
portintegeryesA guest port from the template's exposed ports.
ttl_secondsintegeryesURL lifetime in seconds. Clamped down to 3600 (1h).
protocolstringnotcp (default) — a raw byte tunnel for any TCP (HTTP, WebSocket, Postgres, a preview or env-server). cdp — a DevTools-framed relay a CDP client (connect_over_cdp) consumes directly.

Response 200ConnectUrlResponse:

{
"url": "wss://api.collimate.ai/v1/sandboxes/sbx_9f2a1c7b3e40/connect?port=9222&protocol=cdp&t=…",
"expires_at": "2026-07-17T00:10:00Z"
}

Open url directly, or hand it to connect_over_cdp; the SDK wraps this as connect_url(port) / cdp_url() / port_forward(port) (see connect-from-outside). The token is HMAC-scoped to (tenant, sandbox, port, exp) and is revoked when the sandbox is deleted.

Status: 200 · 401 unauthorized · 403 demo_tier_limit (below Pro) · 404 not_found (unknown or foreign sandbox) · 409 port_not_exposed (the port is not in the template's exposed ports).


The WebSocket the minted URL points at: /v1/sandboxes/{id}/connect?port=<p>[&protocol=cdp]&t=<token>. A WS upgrade whose frames are proxied to the guest port; the guest must be listening. Authenticate with the scoped ?t= token from connect-url or a Bearer col_* key — same Pro/Enterprise gate and ownership check.

Clients don't normally call this directly — open the minted url, pass it to connect_over_cdp, or use the SDK's port_forward.

Status: 101 switching protocols (upgrade) · 401 unauthorized · 403 demo_tier_limit · 404 not_found · 409 port_not_exposed (the port is not in the template's exposed ports).


POST /v1/sandboxes/{id}/suspend · .../resume

Section titled “POST /v1/sandboxes/{id}/suspend · .../resume”

Suspend snapshots a running sandbox to disk and stops the meter; resume restores it. Both return a StateResponse:

{ "id": "sbx_9f2a1c7b3e40", "state": "suspended", "mem_bytes": 41943040 }

mem_bytes (suspend) is the on-disk memory image size. See Suspend & resume.


Destroy a sandbox and reclaim its resources.

{ "deleted": true, "id": "sbx_9f2a1c7b3e40" }

404 if it was already gone.


Aggregated usage for your tenant over a window. Query params from and to (RFC 3339).

{
"from": "2026-07-01T00:00:00Z",
"to": "2026-07-02T00:00:00Z",
"totals": {
"cpu_core_hours": 12.4,
"ram_gb_hours": 24.8,
"disk_gb_hours": 3.1,
"snapshot_gb_months": 0.05
}
}

Every error carries a stable machine code plus an HTTP status:

{ "code": "quota_exceeded", "message": "concurrent sandbox limit reached" }

See Errors for the full catalog and Limits for the numbers.