Supercomputer
API Reference

HTTP

The REST API behind the SDK and CLI: sessions, jobs, volumes, billing.

Everything the Python SDK and super CLI do goes through a versioned JSON API at https://api.supercomputer.sh/v1. Use it directly from any language or from curl. This page documents the routes a user API key can call. Internal and admin routes are not covered.

Authentication

Every request carries a user API key as a bearer token. Keys start with super_sk_; get one from super login or the dashboard.

curl -s https://api.supercomputer.sh/v1/auth/identity \
  -H "Authorization: Bearer $SUPERCOMPUTER_API_KEY"
# {"user_id":"u_...","role":"member","team_ids":[]}

Request bodies are JSON with Content-Type: application/json. Timestamps are RFC 3339. Money is in USD micros (1000000 = $1.00). SKU names are the public short names from GET /v1/skus (for example h100, cpu).

Errors

Errors are JSON with an error message, often a machine-readable code, and a request_id to quote in support requests.

{"error": "job_not_found", "code": "job_not_found", "request_id": "..."}
StatusMeaning
400Invalid body or query.
401Missing or invalid API key.
402 / 403Billing block, or a feature your account cannot use.
404Object missing or owned by someone else.
409State conflict (session closing, spec mismatch, idempotency key reuse).
410Session dead or its filesystem gone (ephemeral).
413Body or file too large.
429Rate limited; honour Retry-After.
503Backend unavailable or session unreachable; retry after Retry-After.

Image specs

image_spec is optional. A session or job that names no image boots the default image for its SKU: the CUDA training image (torch, torchvision, transformers, vLLM pinned) on any GPU box, a slim Python image on a CPU box. These are the images the CLI and SDK boot by default, already baked across the fleet, so they start fastest.

To boot something else, image_spec is a JSON document, sent as a string, describing the image to build: a base registry reference and an ordered list of layers. The smallest valid spec is a bare registry image:

{"base": "pytorch/pytorch:2.9.1-cuda12.8-cudnn9-runtime",
 "layers": [{"type": "base", "params": {"image": "pytorch/pytorch:2.9.1-cuda12.8-cudnn9-runtime"}}]}

Layer types are base, apt_install (packages), pip_install (packages, optional index_url), run_commands (commands) and env (variables). The Python SDK's Image class builds these; call json.dumps(image.to_dict()) to get the string. Images are cached across the fleet by the hash of the spec text, so send a spec byte for byte as you sent it before to hit the cache.

Sessions

A session is a persistent /workspace filesystem that a host brings online on demand. Create one, poll it until it is ready, then run work on it.

Create a session

POST /v1/sessions

FieldTypeNotes
skustringGPU or CPU type. Or sku_preference, an ordered list.
image_specstringImage to boot, as a JSON string. Omit for the SKU default. See Image specs.
coldboolRegister the session without allocating a host. $0 until first resume.
volume_mountsarray[{"name", "mount_path", "read_only"}], composed at setup.
ephemeralboolRun-to-completion session: workspace is never persisted, not resumable.
checkpointboolOpt in to checkpoint/restore on preemption. Off by default.
restartboolRe-run the command on a new box after a host loss. Default true.
keep_warm_secondsintIdle grace before the host reaps the session.
min_disk_gbintFloor on the host root volume.
stale_after_secondsintServer-side lifetime bound for a detached session.

Send an Idempotency-Key header to make retries safe; see retrying session creation.

curl -s -X POST https://api.supercomputer.sh/v1/sessions \
  -H "Authorization: Bearer $SUPERCOMPUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"sku": "h100"}'

Replies:

  • 202 with status: "queued" or "allocating" and retry_after_s: no host yet. Poll GET /v1/sessions/{sid}.
  • 200 with status: "active": the allocation. Fields: sid, cid, hid, host_addr, cert_sha256, token, token_exp, engine, ephemeral.

host_addr, token and cert_sha256 are what the SDK uses to open the host WebSocket for exec, spawn and streaming. That protocol is not documented here; use the Python SDK to run commands, and the HTTP routes below for everything around them.

Read a session

GET /v1/sessions/{sid}

The status code tracks the lifecycle so pollers never infer it from shape:

StatusBody
200Ready: the allocation above with a fresh token, or the full record for a cold or closed session.
202queued or allocating; poll again after retry_after_s. Polling a queued session also keeps it alive.
410dead, with detail.
503unreachable; Retry-After: 5.

Every shape carries sid, status, activity, detail, sku_preference, setup_acked, client_attached, created_at and the stage timestamps.

List sessions

GET /v1/sessions?status=active&limit=100&before=<rfc3339>&include_retired=1

status defaults to active. Returns {"sessions": [...], "limit", "has_more", "next_before"}; pass next_before as before for the next page. Limit is capped at 500.

Lifecycle actions

RouteBodyEffect
POST /v1/sessions/{sid}/resume{"sku", "image_spec", "volume_mounts"} all optionalBring a cold or stopped session online. Same reply shapes as create. image_spec re-baselines the image.
DELETE /v1/sessions/{sid}noneStop the session. Billing stops now; files stay. {"ok": true, "sid", "status"}.
POST /v1/sessions/{sid}/tokennoneMint a fresh host token: {"sid", "cid", "hid", "token", "token_exp"}.
POST /v1/sessions/{sid}/requeuenoneYou were allocated a host you cannot reach: unbind and re-place. 409 if attached; 429 after 3 requeues.
POST /v1/sessions/{sid}/migrate{}Checkpoint and move to a fresh host. Poll the session for the new placement.
POST /v1/sessions/{sid}/volumes{"volume_mounts": [...]} or one {"name", "mount_path", "read_only"}Attach volumes to a live session.
DELETE /v1/sessions/{sid}/volumes/{name}noneFlush and detach one volume.

Files on a live session

These go through the host, for callers that cannot open the WebSocket.

  • POST /v1/sessions/{sid}/files with {"files": [{"path", "content_b64", "mode"}]} writes files into /workspace. Reply: {"ok", "written", "skipped"}.
  • GET /v1/sessions/{sid}/files/{path} returns the file bytes, typed by extension. Files over the host inline cap return 413 file_too_large; read those through /v1/fs after the next publish.

Processes and logs

Durable, served from object storage, so they work after the host is gone.

  • GET /v1/sessions/{sid}/processes returns {"processes": [...], "session_status"}. Each process has process_id, command (argv list), status, exit_code, started_at_ms, ended_at_ms, output_bytes.
  • GET /v1/sessions/{sid}/processes/{pid}/logs?stream=stdout|stderr|both&output=all|tail&output_bytes=N&offset=N returns raw log bytes.
  • GET /v1/sessions/{sid}/logs returns the tail of every process's log, concatenated under ==> command [pid] status <== headers.

Cost and history

  • GET /v1/sessions/{sid}/cost returns {"sid", "compute_usd_micros", "billable_seconds", "intervals": [{"state", "billable", "started_at", "ended_at", "seconds", "sku", "price_usd_micros_per_hour", "amount_usd_micros", "open"}]}.
  • GET /v1/sessions/{sid}/history?limit=N returns {"sid", "status", "lifecycle", "activity", "events": [...], "count", "truncated"}.

Jobs

A job fans one or more commands out as a durable sweep. Each task runs in its own session. See Batch for the model.

Submit a job

POST /v1/jobs

FieldTypeNotes
commandsstring[]Required. One task per command, fully resolved.
namestringResubmitting the same name and spec returns the existing job; a changed spec is 409.
image_specstringImage to boot. Omit for the SKU default; from_session inherits the session's image.
from_sessionstringFork the workspace of a persistent session you own.
sku / sku_preferencestring / string[]Hardware.
volume_mountsarraySame shape as sessions.
envobjectEnvironment for every task.
max_parallelintFan-out cap. Default 8.
retriesintPer-task retries. Default 2.
no_canaryboolSkip the one-task smoke run before fan-out.
canary_commandstringRun this instead of task 0 as the gate.
afterstring[]Job names or ids to wait on. after_strict makes partial success block.
not_before, deadlineRFC 3339Scheduling window.
expected_runtime_s, priorityintHints; priority > 0 is the fast lane.
checkpointboolTri-state checkpoint policy, as for sessions.
webhook_urlstringPOSTed the job status document on completion.

Reply: 200 {"job": {...}, "created": true|false}. Inline workspace manifests are also accepted but require uploading blobs first; use the SDK for that path.

curl -s -X POST https://api.supercomputer.sh/v1/jobs \
  -H "Authorization: Bearer $SUPERCOMPUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
{"name": "lr-sweep", "sku": "h100",
 "commands": ["python train.py --lr 1e-3", "python train.py --lr 3e-4"]}
EOF

Read and manage jobs

{id} accepts a job id or a job name you own.

RouteReply
GET /v1/jobs{"jobs": [...]} with per-state task counts.
GET /v1/jobs/{id}?cost=1{"job", "counts", "tasks", "clusters", "blocked", "window_phase"}. cost=1 adds a per-session cost rollup.
GET /v1/jobs/{id}/attempts?task=NEvery session that ran task N, newest first.
POST /v1/jobs/{id}/cancel body {"remaining": bool}{"ok", "canceled"}. remaining leaves running tasks alone.
POST /v1/jobs/{id}/retry body {"all": bool}Re-queue failed tasks; all also recovers canceled and wedged tasks.
POST /v1/jobs/{id}/settings body {"max_parallel", "priority"}Change a live sweep's fan-out or lane.
POST /v1/jobs/{id}/gcRetire a finished sweep's sessions. 409 job_not_terminal while running.

Job states: waiting, canarying, running, canceling, succeeded, succeeded_partial, failed, canceled. Task states: pending, launching, running, succeeded, failed, canceled. Each task carries index, command, state, attempts, exit_code, error_sig, session_id, process_id.

Volumes

Named, versioned filesystems you mount into sessions.

RouteReply
POST /v1/volumes body {"name"}201 {"volume": {...}}
POST /v1/volumes/{name}/import-session body {"session_id", "source_path", "dest_path"}Copy a stopped session's files into the volume. 409 while either is active.
GET /v1/volumes{"volumes": [{"volume_id", "name", "version", "created_at", "updated_at"}]}
GET /v1/volumes/{name}{"volume": {...}}
DELETE /v1/volumes/{name}{"ok": true}
GET /v1/volumes/{name}/files{"volume", "files": [{"path", "hash", "size", "type", "updated_at"}]}
GET /v1/volumes/{name}/fs/{path}Browse or download, see below.

Filesystem browse

Session workspaces and volumes are served read-only from object storage:

  • GET /v1/fs/{sid}/ and GET /v1/volumes/{name}/fs/ list a directory as HTML. Add ?format=json for {"files": [{"path", "size", "hash"}]} under that prefix.
  • GET /v1/fs/{sid}/path/to/file redirects to a short-lived signed download URL. Range requests work.
  • POST /v1/fs/{sid}/mount-url returns {"token", "path", "expires_at"}. Mount https://api.supercomputer.sh{path} with rclone or any WebDAV-less HTTP mount; no header needed. Ephemeral sessions return 410.

An active session lists files as of its last background sync. A closing session waits for the final manifest.

Catalog

  • GET /v1/skus returns {"skus": [{"name", "label", "vram_gb", "vcpus", "ram_gb", "cost_per_hr", "availability", "effective_concurrency"}], "catalog_status"}. availability is live when idle hosts exist now.
  • GET /v1/billing/prices returns {"prices": [...]}, the current rate card by SKU.
  • GET /v1/health is unauthenticated: {"ok": true, "service": "dispatcher-v2"}.
  • GET /v1/auth/identity returns {"user_id", "role", "team_ids"} for the key in use.

Billing

RouteReply
GET /v1/billing/balance{"balance_usd_micros", "available_usd_micros", "accrued_unposted_usd_micros", "live_rate_usd_micros_per_hour", "spend_blocked", "autorefill", "card", "plan"}
GET /v1/billing/usage?since=&until=Rollup rows with totals_by_resource, totals_by_session, totals_by_api_key. Bounds are RFC 3339 or a duration like 24h; default is the last 30 days.
GET /v1/billing/ledger?before_seq=&limit={"entries": [...], "next_before_seq"}, newest first, limit up to 200.
GET /v1/billing/payment-methodThe card on file.
POST /v1/billing/checkout body {"amount_usd_micros", "success_url", "cancel_url"}{"url", "purchase_id", "checkout_session_id"}; send the user to url to pay.
PUT /v1/billing/autorefill{"enabled", "threshold_usd_micros", "amount_usd_micros", "weekly_cap_usd_micros"}; returns the balance view.
DELETE /v1/billing/payment-methodRemove the card.

Copy groups

POST /v1/copy-groups takes a session create body plus "size": 2..4 and places that many identical sessions together for multi-node work. Reply: 202 {"group_id", "sessions": [...]}. GET /v1/copy-groups/{id} returns {"group", "sessions"} and keeps queued members alive.

Client headers

The SDK sends X-Supercomputer-Client and X-Supercomputer-Client-Version. They are optional. A client that sends a version below the deployment's floor gets 426 client_too_old; a request with no version header is never refused on that basis.

On this page