Instancias
Una instancia es una oferta alquilada que ejecuta una plantilla. Estos endpoints hacen todo lo que hace la página Instancias.
Desplegar una instancia
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}
]
}'
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
offer_id | uuid | Sí | Debe seguir estando available, o la llamada devuelve 409 OFFER_UNAVAILABLE |
template_id | uuid | Sí | Una plantilla de sistema, una pública, o una que pertenezca a su organización |
disk_gb | entero | Sí | Entre 10 y 20000, y no mayor que el machine.disk_gb del host |
label | cadena, hasta 64 caracteres | No | Se muestra en la lista de la consola. Su valor predeterminado es null. |
ssh_key_id | uuid | No | Con una sesión iniciada o una clave de API personal: una de sus propias claves SSH. Con una clave de API team: la clave de cualquier persona que sea miembro de la organización ahora, nunca la de un exmiembro, incluido el creador de la clave si ya se fue. Sin ella, la instancia no tiene ninguna clave autorizada y no podrá conectarse por SSH. |
env_overrides | array de {key, value, secret} | No | Se fusiona sobre el env de la plantilla, emparejado por clave. Una entrada con valor null se descarta. Como máximo 100 entradas; claves de hasta 256 caracteres y valores de hasta 4,096. |
Las sustituciones de entorno se fusionan sobre el env de la plantilla, pero la capa propia de la plataforma gana sobre ambas. No puede ensombrecer JUPYTER_TOKEN, GPU_COUNT ni el token de acceso de la instancia (SUPERHEAT_ACCESS_TOKEN, ni ninguna variable de la plantilla que lo lleve).
La respuesta es 201 con la instancia. En ese momento sus ssh_host y ssh_port todavía son null; se completan cuando la carga de trabajo está en marcha. La facturación empieza cuando la carga de trabajo llega realmente a running, no en el momento de esta llamada.
El saldo tiene que cubrir una hora del consumo total de la organización cuando despliega una instancia, y de nuevo cuando inicia una: la GPU y el disco de la instancia nueva, más la GPU y el disco de cada instancia en ejecución, iniciándose o en creación, y el disco de cada una que esté detenida. No se reserva ni se retiene nada: el tiempo de GPU se factura por segundo mientras la instancia está en ejecución, y el disco por GB y por hora mientras está detenida. Con saldo cero, las instancias en ejecución se detienen automáticamente; tras 24 horas en cero o por debajo, una vez que el saldo está en −$5 o por debajo, las instancias detenidas y en error se destruyen. Consulte Cómo funciona la facturación.
Cuando se rechaza un despliegue
Un despliegue rechazado devuelve uno de estos códigos. El cuerpo lleva, junto a code y message, los campos adicionales que se indican aquí.
| Estado | Código | Cuándo |
|---|---|---|
| 402 | INSUFFICIENT_BALANCE | El saldo no cubre una hora del consumo de la organización con esta instancia añadida. Incluye balance_micro y required_micro |
| 402 | PAYMENTS_FROZEN | Hay una disputa de pago abierta sobre la organización |
| 409 | OFFER_UNAVAILABLE | La oferta no existe, se retiró o ya no le queda ninguna unidad libre, incluida una unidad que otro despliegue tomó mientras se reservaba el suyo |
| 409 | MACHINE_IN_MAINTENANCE | La máquina tiene programado desconectarse demasiado pronto para iniciar en ella. Incluye next_maintenance |
| 409 | MACHINE_DISK_EXHAUSTED | El disco de la máquina ya está comprometido con otros inquilinos. Incluye available_disk_gb y requested_disk_gb |
| 409 | INSTANCE_LIMIT_REACHED | La organización ya tiene 25 instancias sin destruir. Las detenidas y las que están en error cuentan. Incluye limit |
| 409 | OFFER_NOT_PINNABLE | La máquina no está registrada en el plano de control, así que el despliegue no se puede fijar a ella |
| 422 | DISK_TOO_LARGE | disk_gb supera el disco total de la máquina. Incluye max_disk_gb |
| 422 | OFFER_NOT_VM_CAPABLE | Una plantilla vm en una máquina que no puede ejecutar máquinas virtuales |
| 422 | TEMPLATE_COMING_SOON | La imagen de la plantilla todavía no se ha publicado |
| 422 | TEMPLATE_CUDA_TOO_NEW | La plantilla admite CUDA solo hasta su cuda_max, y la máquina informa una versión más reciente |
| 422 | TEMPLATE_ARCH_UNSUPPORTED | La plantilla necesita hardware distinto de x86_64. Todos los hosts de Superheat son x86_64 |
| 422 | TEMPLATE_REQUIRES_OWNER | La plantilla descarga de un registro privado, y solo la organización propietaria puede desplegarla |
| 404 | TEMPLATE_NOT_FOUND | La plantilla no existe, su organización no puede verla o se desactivó |
| 404 | SSH_KEY_NOT_FOUND | ssh_key_id no es una clave que esta credencial pueda adjuntar (vea ssh_key_id más arriba), o no existe |
Todos los códigos de esta tabla se devuelven antes de conservar nada: un despliegue rechazado no deja ninguna instancia atrás y no cuesta nada. Las ofertas de máquinas no registradas no aparecen en GET /v1/offers, así que normalmente solo se encuentra OFFER_NOT_PINNABLE con un id de oferta guardado de antes.
Qué hacer con cada código está en Códigos de error.
Campos de la instancia
{
"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 y template son los objetos documentados en Ofertas y Plantillas; aquí se muestran abreviados. La plantilla incrustada lleva readme y onstart como null: pida GET /v1/templates/{id} cuando los necesite.
| Campo | Tipo | Significado |
|---|---|---|
status | cadena | Uno de creating, starting, running, stopping, stopped, destroying, destroyed, error. Consulte Estados de instancia. |
disk_gb | entero | El disco que pidió, facturado por GB y por hora mientras está detenida |
price_per_hour_micro | entero | Tarifa congelada desde la oferta al momento de alquilar, para el bloque completo |
storage_price_per_gb_hour_micro | entero | Tarifa de disco congelada al momento de alquilar |
ssh_host, ssh_port, ssh_user | cadena o null, entero o null, cadena | El destino de conexión. ssh_host es la dirección IP pública de la máquina GPU. El puerto se asigna desde el rango publicado del host y nunca es el 22. El host y el puerto son null hasta que la carga de trabajo está en marcha. |
jupyter_url | cadena o null | Punto de entrada de JupyterLab, una vez que una plantilla jupyter informa uno. Lleva el token de acceso como ?token= |
open_url | cadena o null | El endpoint del botón de abrir de la plantilla, una vez que se informa. Lleva ?token= cuando el puerto del botón de abrir está protegido por el proxy de acceso |
access_token | cadena o null | El token de acceso de la instancia: el token de JupyterLab, la clave bearer que esperan los puertos de aplicación de su plantilla y la contraseña de cualquier cuenta que la plantilla cree de antemano. null en una plantilla que no usa ninguno, y una vez destruida la instancia. Consulte Puertos y el botón Abrir |
error_code, error_message | cadena o null | Por qué la instancia está en error —por ejemplo provision_failed o workload_completed— o, en una instancia running o stopped, por qué una detención o un inicio no se completó (stop_timed_out, start_timed_out, gpus_unavailable). null en los demás casos. La página de la instancia en la consola explica el código en el idioma de su consola; todos los códigos que conoce están en Códigos de error |
allowed_actions | array | Cuáles de start, stop y destroy acepta la API en el estado actual |
gpus_released | booleano | true una vez que las GPU de la instancia detenida se han liberado de vuelta a la máquina: el saldo llegó a cero, o una disputa de pago congeló los pagos de la organización. Su contenedor y su disco siguen ahí, y un inicio tiene que recuperar las mismas GPU: responde 409 CAPACITY_UNAVAILABLE mientras otro cliente use una de ellas. Consulte Detener vs. destruir |
gpu_release | cadena o null | En qué punto está una liberación: pending (decidida, aún sin confirmar por la máquina), released, o unsupported (la máquina no puede liberar GPU, o la instancia ejecuta una plantilla vm, así que siguen reservadas y la instancia factura solo el almacenamiento, como tras su propia detención). null cuando no se decidió ninguna liberación |
gpu_release_requested_at | marca de tiempo o null | Cuándo se decidió la liberación |
stop_releases_gpus | booleano | true mientras una disputa de pago tenga congelados los pagos de la organización: una detención solicitada ahora libera las GPU, donde la máquina lo permite, en lugar de mantenerlas reservadas |
hold_price_per_hour_micro, stop_hold_price_per_hour_micro, suspended_hold_price_per_hour_micro | entero o null | Reservados para una tarifa de retención de GPU en instancias detenidas. No se cobra ninguna —una instancia detenida factura solo el almacenamiento—, así que los tres son null |
created_at, started_at, status_changed_at, destroyed_at | marcas de tiempo | started_at se establece la primera vez que se ejecuta la carga de trabajo |
spend_micro | entero | Cargos liquidados de esta instancia hasta ahora. Se mueve con cada liquidación, en la misma transacción que la fila del libro mayor, así que siempre es igual a la suma de los cargos de la instancia en la lista de transacciones |
deployed_by | cadena | Correo del miembro que la desplegó. En una instancia desplegada con una clave de API team, en su lugar la clave: su nombre y su prefijo, como CI deploys (shk_1a2b3c4d…) |
deployed_via_api_key | objeto o null | La clave de API con la que se desplegó la instancia —id, name, kind (team o personal), prefix y revoked—, o null para un despliegue desde la consola y para las instancias desplegadas antes de que esto se registrara |
Listar instancias
curl -s "$SUPERHEAT_API/v1/instances" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
Devuelve {"items": [...]} para la organización activa, de la más nueva a la más antigua. Las instancias destruidas quedan excluidas a menos que pase include_destroyed=true.
Obtener una sola instancia
curl -s "$SUPERHEAT_API/v1/instances/e08b5f27-1c4a-4d90-b3e6-72a9d1f45c83" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
Los ids desconocidos, y las instancias que pertenecen a otra organización, devuelven 404 INSTANCE_NOT_FOUND.
Detener, iniciar y destruir
| Solicitud | Efecto | Permitido desde |
|---|---|---|
POST /v1/instances/{id}/stop | Apaga el contenedor, conserva el disco y mantiene reservada la ranura de GPU, o, mientras una disputa de pago tenga congelados los pagos de la organización, libera las GPU donde la máquina lo permite (stop_releases_gpus). El estado pasa a stopping y luego a stopped. | running |
POST /v1/instances/{id}/start | Vuelve a levantar una instancia detenida sobre el mismo disco y las mismas GPU, que una instancia con gpus_released tiene que recuperar. El estado pasa a starting y luego a running. | stopped |
DELETE /v1/instances/{id} | Desmonta la instancia y libera el bloque. El estado pasa a destroying y luego a destroyed. Sobre una instancia que ya está en destroying, vuelve a enviar el desmontaje y devuelve 200. | todos los estados salvo destroyed |
curl -s -X POST "$SUPERHEAT_API/v1/instances/$INSTANCE_ID/stop" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
Las tres devuelven el objeto completo de la instancia en su nuevo estado de transición: la transición termina de forma asíncrona, así que sondee hasta que el estado se estabilice.
Llamar a una de estas desde un estado que no lo permite devuelve 409 INVALID_STATE con un mensaje que nombra el estado actual, por ejemplo Cannot start an instance while it is running. allowed_actions en la instancia indica lo que es válido en este momento. Iniciar vuelve a comprobar el saldo, que tiene que cubrir una hora del consumo de la organización con esta instancia en marcha, y puede devolver 402 INSUFFICIENT_BALANCE. Mientras haya una disputa de pago abierta, devuelve 402 PAYMENTS_FROZEN.
Un inicio también falla cuando el host no puede aceptarlo. En cada caso la instancia vuelve a stopped, con su disco, y con su ranura salvo que sus GPU se hayan liberado:
| Estado | Código | Cuándo |
|---|---|---|
| 409 | CAPACITY_UNAVAILABLE | Las GPU de la instancia se liberaron y otro cliente está usando una de ellas ahora. Vuelva a intentarlo más tarde, o copie sus datos y destrúyala |
| 409 | HOST_UNREACHABLE | La máquina en la que vive la instancia no está conectada. Inténtelo de nuevo más tarde |
| 409 | START_REFUSED | El host rechazó la reanudación, o ya no conserva la carga de trabajo; el mensaje dice cuál de las dos. En el segundo caso, destruya la instancia y vuelva a desplegar |
| 503 | START_UNAVAILABLE | La reanudación no pudo completarse en este momento. Inténtelo de nuevo en breve |
La detención y la destrucción se registran primero y se envían al host después, y la plataforma las sigue reenviando hasta que el host las haya hecho. Una detención que el host no ha confirmado tras 30 minutos devuelve la instancia a running, facturando la GPU, y la detención se sigue reintentando; error_code indica stop_timed_out.
Cada reenvío de una misma detención, inicio o destrucción lleva la misma identidad, y cada petición nueva que usted hace recibe otra. Así, una detención reenviada después de que usted ya haya vuelto a iniciar la instancia se reconoce como obsoleta y no la detiene una segunda vez, y un inicio que la plataforma reintenta cuando ya se había completado deja de responderse como un rechazo. Sus propias llamadas no necesitan nada más: envíe otra vez DELETE si quiere que se reenvíe la baja, y se trata como una petición nueva.
DELETE es definitivo: el contenedor, el disco y todo lo que hay en él desaparecen, y la oferta vuelve al mercado. Detenga en su lugar si quiere que sus datos lo estén esperando. Consulte Detener vs. destruir.
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"
]
}
| Parámetro | Rango | Predeterminado |
|---|---|---|
tail | 1 a 1000 | 200 |
Los valores fuera de ese rango se rechazan con 422. lines está vacío hasta que la carga de trabajo se haya ejecutado por primera vez, así que una instancia en creating no devuelve nada. No hay endpoint de streaming; sondee este — la consola lo actualiza cada tres segundos. Consulte Leer los logs.
Desplegar y conectarse, de principio a fin
Este es el camino completo desde una shell vacía hasta una sesión SSH. Da por hecho que tiene jq, una clave SSH ya agregada en la consola y créditos en el saldo.
1. Defina sus credenciales. Las claves SSH pertenecen a su cuenta y no a la organización, así que listarlas necesita un token de sesión; todo lo demás funciona con la clave de API.
export SUPERHEAT_API="https://<your-superheat-api-host>"
export SUPERHEAT_KEY="shk_your_key_here"
AUTH=(-H "Authorization: Bearer $SUPERHEAT_KEY")
2. Encuentre el id de la clave SSH con un token de sesión de un navegador con la sesión iniciada:
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. Elija el bloque de una sola H100 más barato:
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. Elija una plantilla SSH:
TEMPLATE_ID=$(curl -s "$SUPERHEAT_API/v1/templates?tab=recommended&mode=ssh" \
"${AUTH[@]}" | jq -r '.items[0].id')
5. Despliegue:
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. Espere a 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. Construya el comando de conexión a partir de la propia instancia en lugar de reconstruirlo: el puerto se asigna por instancia:
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. Conéctese y compruebe las GPUs:
ssh -p 41207 root@203.0.113.14 nvidia-smi
9. Detenga cuando haga una pausa, destruya cuando haya terminado:
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'