Instances
An instance is one rented offer running one template. These endpoints do everything the Instances page does.
Deploy an instance
curl -s -X POST "$SUPERHEAT_API/v1/instances" \
-H "Authorization: Bearer $SUPERHEAT_KEY" \
-H "Content-Type: application/json" \
-d '{
"offer_id": "5d2f9c31-8b64-4c0e-9a77-2e0f1b6a4c11",
"template_id": "b1f4a6d2-90c7-5e33-8a2b-1d7c4e0f9a56",
"disk_gb": 60,
"label": "sft-run-14",
"ssh_key_id": "7a3c1e08-42bd-4f19-9d63-5b8e0c2a1f40",
"env_overrides": [
{"key": "HF_TOKEN", "value": "hf_...", "secret": true}
]
}'
| Field | Type | Required | Notes |
|---|---|---|---|
offer_id | uuid | Yes | Must still be available, or the call returns 409 OFFER_UNAVAILABLE |
template_id | uuid | Yes | A system template, a public one, or one your organization owns |
disk_gb | integer | Yes | Between 10 and 20000, and no larger than the host's machine.disk_gb |
label | string, up to 64 characters | No | Shows in the console list. Defaults to null. |
ssh_key_id | uuid | No | Must be a key on the account of whoever holds the credential. Without it, the instance has no authorized key and you cannot SSH in. |
env_overrides | array of {key, value, secret} | No | Merged over the template's env, matched by key. An entry with a null value is dropped. |
Environment overrides are merged over the template's env, but the platform's own overlay wins over both. You cannot shadow JUPYTER_TOKEN or GPU_COUNT.
The response is 201 with the instance. Billing starts when the workload actually reaches running, not at the moment of this call.
Balance is checked at deploy, not reserved. GPU time is billed per second while the instance is running, and disk per GB per hour while it is stopped. At a zero balance running instances are stopped automatically, and at −$5 they are destroyed. See How billing works.
Instance fields
{
"id": "e08b5f27-1c4a-4d90-b3e6-72a9d1f45c83",
"label": "sft-run-14",
"status": "creating",
"disk_gb": 60,
"price_per_hour_microusd": 2290000,
"storage_price_per_gb_hour_microusd": 250,
"ssh_host": "sh-us-tx-01.ssh.superheat.dev",
"ssh_port": 41207,
"ssh_user": "root",
"jupyter_url": null,
"open_url": null,
"created_at": "2026-07-24T11:12:03.771Z",
"started_at": null,
"status_changed_at": "2026-07-24T11:12:03.771Z",
"destroyed_at": null,
"spend_microusd": 0,
"deployed_by": "you@example.com",
"offer": { "id": "5d2f9c31-8b64-4c0e-9a77-2e0f1b6a4c11" },
"template": { "id": "b1f4a6d2-90c7-5e33-8a2b-1d7c4e0f9a56" }
}
offer and template are the complete objects documented in Offers and Templates; they are shown abbreviated here.
| Field | Type | Meaning |
|---|---|---|
status | string | One of creating, starting, running, stopping, stopped, destroying, destroyed, error. See Instance states. |
disk_gb | integer | Disk you asked for, billed per GB per hour while stopped |
price_per_hour_microusd | integer | Rate snapshotted from the offer at rent time, for the whole slice |
storage_price_per_gb_hour_microusd | integer | Disk rate snapshotted at rent time |
ssh_host, ssh_port, ssh_user | string, integer, string | The connect target. The port is assigned from the host's published range and is never 22. |
jupyter_url | string or null | JupyterLab entry point, once a jupyter template reports one |
open_url | string or null | The template's open-button endpoint, once it is reported |
created_at, started_at, status_changed_at, destroyed_at | timestamps | started_at is set the first time the workload runs |
spend_microusd | integer | Settled charges for this instance so far |
deployed_by | string | Email of the member who deployed it |
List instances
curl -s "$SUPERHEAT_API/v1/instances" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
Returns {"items": [...]} for the active organization, newest first. Destroyed instances are excluded unless you pass include_destroyed=true.
Get one instance
curl -s "$SUPERHEAT_API/v1/instances/e08b5f27-1c4a-4d90-b3e6-72a9d1f45c83" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
Unknown ids, and instances belonging to another organization, return 404 INSTANCE_NOT_FOUND.
Stop, start and destroy
| Request | Effect | Allowed from |
|---|---|---|
POST /v1/instances/{id}/stop | Shuts the container down, keeps the disk and holds the GPU slot. Status goes to stopping, then stopped. | running |
POST /v1/instances/{id}/start | Brings a stopped instance back on the same disk. Status goes to starting, then running. | stopped |
DELETE /v1/instances/{id} | Tears the instance down and releases the slice. Status goes to destroying, then destroyed. | running, stopped, error |
curl -s -X POST "$SUPERHEAT_API/v1/instances/$INSTANCE_ID/stop" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
All three return the full instance object at its new transitional status — the transition finishes asynchronously, so poll until the status settles.
Calling one of these from a status that does not allow it returns 409 INVALID_STATE with a message naming the current status, for example Cannot start an instance while it is running. Starting also re-checks the balance and can return 402 INSUFFICIENT_BALANCE.
DELETE is final: the container, the disk and everything on it are gone, and the offer goes back on the market. Stop instead if you want your data waiting for you. See Stop vs destroy.
Logs
curl -s "$SUPERHEAT_API/v1/instances/$INSTANCE_ID/logs?tail=50" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
{
"lines": [
"[2026-07-24 11:12:07] superheat-agent: pulling image vastai/pytorch",
"[2026-07-24 11:12:11] superheat-agent: image ready, creating container",
"[2026-07-24 11:12:13] nvidia-smi: detected 1 GPU(s), driver 570.86",
"[2026-07-24 11:12:14] sshd: listening on 0.0.0.0:41207",
"[2026-07-24 11:12:15] superheat-agent: instance is ready"
]
}
| Parameter | Range | Default |
|---|---|---|
tail | 1 to 1000 | 200 |
Values outside that range are rejected with 422. lines is empty until the workload has run for the first time, so a creating instance returns nothing. There is no streaming endpoint; poll this one — the console refreshes it every three seconds. See Logs.
Deploy and connect, end to end
This is the whole path from an empty shell to an SSH session. It assumes jq, an SSH key already added in the console, and credits on the balance.
1. Set your credentials. SSH keys belong to your account rather than to the organization, so listing them needs a session token; everything else runs on the API key.
export SUPERHEAT_API="https://<your-superheat-api-host>"
export SUPERHEAT_KEY="shk_your_key_here"
AUTH=(-H "Authorization: Bearer $SUPERHEAT_KEY")
2. Find the SSH key id with a session token from a signed-in browser:
curl -s "$SUPERHEAT_API/v1/ssh-keys" \
-H "Authorization: Bearer $SESSION_TOKEN" \
| jq -r '.items[] | "\(.id) \(.name) \(.fingerprint)"'
7a3c1e08-42bd-4f19-9d63-5b8e0c2a1f40 laptop SHA256:Yx1r0oW2fS7Tq8kJ3mN4pB6vC9dE0gH2iK5lM8nP1qR
SSH_KEY_ID="7a3c1e08-42bd-4f19-9d63-5b8e0c2a1f40"
3. Pick the cheapest single H100 slice:
OFFER_ID=$(curl -s "$SUPERHEAT_API/v1/offers?gpu_model=H100%20SXM&num_gpus=1&sort=price_asc" \
"${AUTH[@]}" | jq -r '.items[0].id')
4. Pick an SSH template:
TEMPLATE_ID=$(curl -s "$SUPERHEAT_API/v1/templates?tab=recommended&mode=ssh" \
"${AUTH[@]}" | jq -r '.items[0].id')
5. Deploy:
INSTANCE_ID=$(curl -s -X POST "$SUPERHEAT_API/v1/instances" \
"${AUTH[@]}" -H "Content-Type: application/json" \
-d "{\"offer_id\":\"$OFFER_ID\",\"template_id\":\"$TEMPLATE_ID\",\"disk_gb\":60,\"label\":\"api-demo\",\"ssh_key_id\":\"$SSH_KEY_ID\"}" \
| jq -r '.id')
6. Wait for running:
while :; do
STATUS=$(curl -s "$SUPERHEAT_API/v1/instances/$INSTANCE_ID" "${AUTH[@]}" | jq -r '.status')
echo "$STATUS"
case "$STATUS" in
running) break ;;
error|destroyed) exit 1 ;;
esac
sleep 3
done
7. Build the connect command from the instance itself rather than reconstructing it — the port is assigned per instance:
curl -s "$SUPERHEAT_API/v1/instances/$INSTANCE_ID" "${AUTH[@]}" \
| jq -r '"ssh -p \(.ssh_port) \(.ssh_user)@\(.ssh_host)"'
ssh -p 41207 root@sh-us-tx-01.ssh.superheat.dev
8. Connect and check the GPUs:
ssh -p 41207 root@sh-us-tx-01.ssh.superheat.dev nvidia-smi
9. Stop when you pause, destroy when you are done:
curl -s -X POST "$SUPERHEAT_API/v1/instances/$INSTANCE_ID/stop" "${AUTH[@]}" | jq -r '.status'
curl -s -X DELETE "$SUPERHEAT_API/v1/instances/$INSTANCE_ID" "${AUTH[@]}" | jq -r '.status'