執行個體
一個執行個體就是一項租下的報價,執行一個範本。這些端點做的事,跟 執行個體 頁面做的完全一樣。
部署執行個體
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}
]
}'
| 欄位 | 型別 | 必填 | 備註 |
|---|---|---|---|
offer_id | uuid | 是 | 必須仍是 available,否則呼叫會回傳 409 OFFER_UNAVAILABLE |
template_id | uuid | 是 | 系統範本、公開範本,或你的組織擁有的範本 |
disk_gb | 整數 | 是 | 介於 10 與 20000 之間,且不得大於主機的 machine.disk_gb |
label | 字串,最多 64 個字元 | 否 | 會顯示在主控台清單中。預設為 null。 |
ssh_key_id | uuid | 否 | 使用已登入的工作階段或 personal API 金鑰時:你自己的一把 SSH 金鑰。使用 team API 金鑰時:目前任何一位組織成員的金鑰——絕不能是已離開成員的,包括已離開的金鑰建立者本人。沒有它,執行個體上就沒有授權金鑰,你也就無法 SSH 進去。 |
env_overrides | {key, value, secret} 的陣列 | 否 | 依 key 比對,覆蓋在範本的 env 之上。值為 null 的項目會被捨棄。最多 100 個項目;key 最多 256 個字元,值最多 4,096 個字元。 |
環境變數覆寫會蓋在範本的 env 之上,但平台自己的覆蓋層又贏過這兩者。你無法蓋掉 JUPYTER_TOKEN、GPU_COUNT 或執行個體存取權杖(SUPERHEAT_ACCESS_TOKEN,以及任何承載它的範本變數)。
回應是 201 加上執行個體。這時其中的 ssh_host 與 ssh_port 還是 null,要等工作負載起來之後才會填上。計費從工作負載真正進入 running 時開始,不是在這個呼叫的當下。
部署一個執行個體時,以及之後每次啟動時,餘額都必須足以支付組織整體一小時的消耗:新執行個體的 GPU 與硬碟,加上每個執行中、啟動中或建立中執行個體的 GPU 與硬碟,以及每個已停止執行個體的硬碟。但不會預留或圈住任何金額:執行個體執行期間,GPU 時間按秒計費;停止期間,硬碟按每 GB 每小時計費。餘額歸零時執行中的執行個體會被自動停止;餘額在零或以下持續 24 小時、且已達 −$5 或更低之後,已停止與處於 error 的執行個體會被銷毀。請參閱計費如何運作。
部署被拒絕時
被拒絕的部署會回傳下列代碼之一。回應內容除了 code 與 message,還會帶上這裡列出的額外欄位。
| 狀態碼 | 代碼 | 何時出現 |
|---|---|---|
| 402 | INSUFFICIENT_BALANCE | 餘額不足以支付組織加上這個執行個體之後一小時的消耗。帶有 balance_micro 與 required_micro |
| 402 | PAYMENTS_FROZEN | 這個組織還有一筆尚未解決的付款爭議 |
| 409 | OFFER_UNAVAILABLE | 報價不存在、已下架,或已經沒有空閒單位——包括你的部署正在預留時,被另一個部署拿走的單位 |
| 409 | MACHINE_IN_MAINTENANCE | 這台機器很快就要依排程下線,來不及在上面啟動。帶有 next_maintenance |
| 409 | MACHINE_DISK_EXHAUSTED | 這台機器的硬碟已經許諾給其他租戶了。帶有 available_disk_gb 與 requested_disk_gb |
| 409 | INSTANCE_LIMIT_REACHED | 這個組織已經有 25 個尚未銷毀的執行個體。已停止與處於 error 的執行個體也算在內。帶有 limit |
| 409 | OFFER_NOT_PINNABLE | 這台機器沒有在控制平面註冊,所以部署無法固定到它上面 |
| 422 | DISK_TOO_LARGE | disk_gb 超過這台機器的硬碟總量。帶有 max_disk_gb |
| 422 | OFFER_NOT_VM_CAPABLE | 把 vm 範本指到了無法執行虛擬機器的機器上 |
| 422 | TEMPLATE_COMING_SOON | 範本的映像檔還沒有發布 |
| 422 | TEMPLATE_CUDA_TOO_NEW | 範本最高只支援到它的 cuda_max,而這台機器回報的 CUDA 版本比較新 |
| 422 | TEMPLATE_ARCH_UNSUPPORTED | 範本需要 x86_64 以外的硬體。所有 Superheat 主機都是 x86_64 |
| 422 | TEMPLATE_REQUIRES_OWNER | 範本從私有登錄庫拉取,只有擁有它的組織才能部署 |
| 404 | TEMPLATE_NOT_FOUND | 範本不存在、你的組織看不到它,或它已被停用 |
| 404 | SSH_KEY_NOT_FOUND | ssh_key_id 不是這個憑證可以附加的金鑰(見上面的 ssh_key_id),或者不存在 |
這張表裡的每個代碼,都在任何東西被保留下來之前就回傳:被拒絕的部署不會留下執行個體,也不花任何錢。未註冊機器上的報價不會出現在 GET /v1/offers 中,所以通常只有拿著先前存下的報價 id 時才會碰到 OFFER_NOT_PINNABLE。
每個代碼該怎麼處理,請參閱錯誤代碼。
執行個體欄位
{
"id": "e08b5f27-1c4a-4d90-b3e6-72a9d1f45c83",
"label": "sft-run-14",
"status": "creating",
"disk_gb": 60,
"price_per_hour_micro": 2290000,
"storage_price_per_gb_hour_micro": 250,
"ssh_host": null,
"ssh_port": null,
"ssh_user": "root",
"jupyter_url": null,
"open_url": null,
"access_token": null,
"error_code": null,
"error_message": null,
"allowed_actions": ["destroy"],
"gpus_released": false,
"gpu_release": null,
"gpu_release_requested_at": null,
"stop_releases_gpus": false,
"hold_price_per_hour_micro": null,
"stop_hold_price_per_hour_micro": null,
"suspended_hold_price_per_hour_micro": 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_micro": 0,
"deployed_by": "you@example.com",
"deployed_via_api_key": null,
"offer": { "id": "5d2f9c31-8b64-4c0e-9a77-2e0f1b6a4c11" },
"template": { "id": "b1f4a6d2-90c7-5e33-8a2b-1d7c4e0f9a56" }
}
offer 與 template 是報價與範本中記載的物件;這裡只是縮略顯示。內嵌的範本會把 readme 與 onstart 帶成 null——需要它們時,請呼叫 GET /v1/templates/{id}。
| 欄位 | 型別 | 意義 |
|---|---|---|
status | 字串 | creating、starting、running、stopping、stopped、destroying、destroyed、error 其中之一。請參閱執行個體狀態。 |
disk_gb | 整數 | 你要求的硬碟容量,停止期間按每 GB 每小時計費 |
price_per_hour_micro | 整數 | 租用當下從報價快照下來的費率,涵蓋整個切片 |
storage_price_per_gb_hour_micro | 整數 | 租用當下快照下來的硬碟費率 |
ssh_host, ssh_port, ssh_user | 字串或 null、整數或 null、字串 | 連線目標。ssh_host 是這台 GPU 機器的公開 IP 位址。連接埠是從主機公開的範圍中指派的,永遠不會是 22。工作負載起來之前,主機與連接埠都是 null。 |
jupyter_url | 字串或 null | JupyterLab 進入點,在 jupyter 範本回報之後出現。以 ?token= 帶著存取權杖 |
open_url | 字串或 null | 範本的開啟按鈕端點,在它被回報之後出現。當開啟按鈕的連接埠由存取代理守護時,會帶著 ?token= |
access_token | 字串或 null | 執行個體的存取權杖:JupyterLab 權杖、範本應用程式連接埠所要求的 bearer 金鑰,以及範本預先建立之帳號的密碼。範本不使用權杖時為 null,執行個體銷毀後也是 null。請參閱連接埠與開啟按鈕 |
error_code, error_message | 字串或 null | 執行個體為什麼處於 error——例如 provision_failed 或 workload_completed——或者,在 running 或 stopped 的執行個體上,停止或啟動為什麼沒有落地(stop_timed_out、start_timed_out、gpus_unavailable)。其他情況為 null。主控台的執行個體頁面會用你的主控台語言解釋這個代碼;它認得的每個代碼都列在錯誤代碼中 |
allowed_actions | 陣列 | 在目前狀態下,API 接受 start、stop、destroy 中的哪些 |
gpus_released | 布林值 | 已停止執行個體的 GPU 被釋回機器之後為 true — 餘額到了零,或一筆付款爭議凍結了組織的付款。它的容器與硬碟還在,啟動必須取回同樣的 GPU:只要另一位租用者正在使用其中一張,就會回傳 409 CAPACITY_UNAVAILABLE。請參閱停止與銷毀 |
gpu_release | 字串或 null | 釋放進行到哪一步:pending(已決定,機器尚未確認)、released,或 unsupported(機器無法釋放 GPU,或執行個體執行的是 vm 範本,所以它們繼續保留,執行個體只收取儲存費,和你自己停止之後一樣)。沒有決定釋放時為 null |
gpu_release_requested_at | 時間戳記或 null | 決定釋放的時間 |
stop_releases_gpus | 布林值 | 當一筆付款爭議凍結了組織的付款時為 true:此時要求的停止會在機器支援的情況下釋放 GPU,而不是繼續保留它們 |
hold_price_per_hour_micro、stop_hold_price_per_hour_micro、suspended_hold_price_per_hour_micro | 整數或 null | 為已停止執行個體的 GPU 保留費預留的欄位。目前不收取這種費用 — 已停止的執行個體只收取儲存費 — 所以這三個欄位都是 null |
created_at, started_at, status_changed_at, destroyed_at | 時間戳記 | started_at 在工作負載第一次執行時設定 |
spend_micro | 整數 | 這個執行個體目前已結算的費用。它隨每一次結算變動,並與帳本記錄在同一個交易中寫入,所以它永遠等於這個執行個體在交易清單上所有扣費的總和 |
deployed_by | 字串 | 部署它的成員的電子郵件。用 team API 金鑰部署的執行個體,這裡顯示的是金鑰本身:它的名稱與前綴,例如 CI deploys (shk_1a2b3c4d…) |
deployed_via_api_key | 物件或 null | 部署這個執行個體所用的 API 金鑰——id、name、kind(team 或 personal)、prefix 與 revoked——主控台部署的執行個體,以及在開始記錄這一項之前部署的執行個體,為 null |
列出執行個體
curl -s "$SUPERHEAT_API/v1/instances" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
回傳目前組織的 {"items": [...]},最新的排前面。除非你帶上 include_destroyed=true,否則已銷毀的執行個體不會包含在內。
取得單一執行個體
curl -s "$SUPERHEAT_API/v1/instances/e08b5f27-1c4a-4d90-b3e6-72a9d1f45c83" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
未知的 id,以及屬於別的組織的執行個體,都會回傳 404 INSTANCE_NOT_FOUND。
停止、啟動與銷毀
| 請求 | 效果 | 可從哪些狀態執行 |
|---|---|---|
POST /v1/instances/{id}/stop | 關閉容器,保留硬碟並保住 GPU 名額 — 或在一筆付款爭議凍結了組織的付款期間,在機器支援的情況下釋放 GPU(stop_releases_gpus)。狀態變成 stopping,接著是 stopped。 | running |
POST /v1/instances/{id}/start | 用同一顆硬碟與同樣的 GPU 把已停止的執行個體叫回來;gpus_released 的執行個體必須重新取回這些 GPU。狀態變成 starting,接著是 running。 | stopped |
DELETE /v1/instances/{id} | 拆掉執行個體並釋放切片。狀態變成 destroying,接著是 destroyed。對已經處於 destroying 的執行個體,它會重新送出拆除並回傳 200。 | destroyed 以外的每個狀態 |
curl -s -X POST "$SUPERHEAT_API/v1/instances/$INSTANCE_ID/stop" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
這三個都會回傳處於新的過渡狀態的完整執行個體物件 —— 轉換是非同步完成的,所以請持續輪詢直到狀態穩定下來。
從不允許的狀態呼叫其中之一,會回傳 409 INVALID_STATE,訊息中會指出目前的狀態,例如 Cannot start an instance while it is running。執行個體上的 allowed_actions 會列出此刻合法的動作。啟動時會重新檢查餘額,餘額必須足以支付組織在這個執行個體執行時一小時的消耗,否則回傳 402 INSUFFICIENT_BALANCE。付款爭議尚未解決期間,啟動會回傳 402 PAYMENTS_FROZEN。
主機無法接手時,啟動也會失敗。每一種情況下,執行個體都會回到 stopped,硬碟保留著 — 名額也是,除非它的 GPU 已被釋放:
| 狀態碼 | 代碼 | 何時出現 |
|---|---|---|
| 409 | CAPACITY_UNAVAILABLE | 執行個體的 GPU 已被釋放,而另一位租用者現在正在使用其中一張。稍後再試,或先把資料複製出來再銷毀它 |
| 409 | HOST_UNREACHABLE | 執行個體所在的機器目前沒有連線。請稍後再試 |
| 409 | START_REFUSED | 主機拒絕恢復,或已不再持有該工作負載——訊息會說明是哪一種。若是後者,請銷毀執行個體並重新部署 |
| 503 | START_UNAVAILABLE | 目前無法完成恢復。請稍候再試 |
停止與銷毀會先被記錄下來,之後才送到主機,而平台會一直重送,直到主機完成為止。主機在 30 分鐘後仍未確認的停止,會讓執行個體回到 running、重新計費 GPU,並繼續重試停止;error_code 會是 stop_timed_out。
同一次停止、啟動或銷毀的每一次重送都帶著同一個識別,而你發出的每個新請求都會得到一個新的。所以在你已經重新啟動執行個體之後才重送的那次停止,會被認定為過時,不會再把它停一次;平台在啟動已經生效之後才重試的那次啟動,也不會再被當成拒絕回覆。你自己的呼叫不需要做任何額外的事:如果想讓拆除再送一次,就再送一次 DELETE,它會被當成一個新請求。
DELETE 是不可逆的:容器、硬碟以及上面的所有東西都會消失,而報價會回到市集上。如果你希望資料還在那裡等你,請改用停止。請參閱停止與銷毀的差別。
日誌
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"
]
}
| 參數 | 範圍 | 預設 |
|---|---|---|
tail | 1 到 1000 | 200 |
超出該範圍的值會被 422 拒絕。在工作負載第一次執行之前 lines 都是空的,所以處於 creating 的執行個體什麼都不會回傳。沒有串流端點;請輪詢這一個 —— 主控台每三秒重新整理一次。請參閱日誌。
從頭到尾:部署並連線
這是從一個空殼子到 SSH 工作階段的完整路徑。前提是你有 jq、已在主控台加入 SSH 金鑰,而且餘額裡有錢。
1. 設定你的憑證。 SSH 金鑰屬於你的帳號而不是組織,所以列出它們需要工作階段權杖;其他一切都用 API 金鑰跑。
export SUPERHEAT_API="https://<your-superheat-api-host>"
export SUPERHEAT_KEY="shk_your_key_here"
AUTH=(-H "Authorization: Bearer $SUPERHEAT_KEY")
2. 找出 SSH 金鑰 id,用已登入瀏覽器取得的工作階段權杖:
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. 挑最便宜的單張 H100 切片:
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. 挑一個 SSH 範本:
TEMPLATE_ID=$(curl -s "$SUPERHEAT_API/v1/templates?tab=recommended&mode=ssh" \
"${AUTH[@]}" | jq -r '.items[0].id')
5. 部署:
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. 等待進入 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. 從執行個體本身組出連線指令,不要自己拼湊 —— 連接埠是每個執行個體各自指派的:
curl -s "$SUPERHEAT_API/v1/instances/$INSTANCE_ID" "${AUTH[@]}" \
| jq -r '"ssh -p \(.ssh_port) \(.ssh_user)@\(.ssh_host)"'
ssh -p 41207 root@203.0.113.14
8. 連線並檢查 GPU:
ssh -p 41207 root@203.0.113.14 nvidia-smi
9. 暫停時停止,做完時銷毀:
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'