Skip to main content

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}
]
}'
FieldTypeRequiredNotes
offer_iduuidYesMust still be available, or the call returns 409 OFFER_UNAVAILABLE
template_iduuidYesA system template, a public one, or one your organization owns
disk_gbintegerYesBetween 10 and 20000, and no larger than the host's machine.disk_gb
labelstring, up to 64 charactersNoShows in the console list. Defaults to null.
ssh_key_iduuidNoMust 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_overridesarray of {key, value, secret}NoMerged 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.

A deploy spends money the moment it runs

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.

FieldTypeMeaning
statusstringOne of creating, starting, running, stopping, stopped, destroying, destroyed, error. See Instance states.
disk_gbintegerDisk you asked for, billed per GB per hour while stopped
price_per_hour_microusdintegerRate snapshotted from the offer at rent time, for the whole slice
storage_price_per_gb_hour_microusdintegerDisk rate snapshotted at rent time
ssh_host, ssh_port, ssh_userstring, integer, stringThe connect target. The port is assigned from the host's published range and is never 22.
jupyter_urlstring or nullJupyterLab entry point, once a jupyter template reports one
open_urlstring or nullThe template's open-button endpoint, once it is reported
created_at, started_at, status_changed_at, destroyed_attimestampsstarted_at is set the first time the workload runs
spend_microusdintegerSettled charges for this instance so far
deployed_bystringEmail 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

RequestEffectAllowed from
POST /v1/instances/{id}/stopShuts the container down, keeps the disk and holds the GPU slot. Status goes to stopping, then stopped.running
POST /v1/instances/{id}/startBrings 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.

Destroying deletes the disk

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"
]
}
ParameterRangeDefault
tail1 to 1000200

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'