API keys
An API key is the credential you give a script, a CI job or your own tooling. It authenticates as a member of one organization and never expires on its own.
Create a key
In the console, open API Keys and choose Create key. The same page's API endpoint card shows the base URL to send requests to, and an example command that lists the organization's instances — it reads the key from $SUPERHEAT_API_KEY. Over the API:
curl -s -X POST "$SUPERHEAT_API/v1/api-keys" \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "ci-pipeline", "kind": "personal"}'
| Field | Type | Notes |
|---|---|---|
name | string, 1–64 characters | Required. How the key is labeled in the console. |
kind | personal or team | Defaults to personal. team keys are admin-managed and require an admin session to create. When the creator is removed from the organization, personal keys are revoked with them; team keys are not. |
The response returns the key metadata and the secret:
{
"key": {
"id": "0f5a1c93-6d21-4e7c-a0b8-3c9f2e1d4a77",
"name": "ci-pipeline",
"kind": "personal",
"prefix": "shk_9f3a21c4",
"creator_email": "you@example.com",
"creator_id": "4b7e9c12-3f5a-4d8e-b1c6-9a2f0e7d3c58",
"created_at": "2026-07-24T11:02:44.318Z",
"last_used_at": null,
"creator_is_member": true
},
"secret": "shk_9f3a21c4e0b7d5628a1f3c47b9e0d2a6f81c53d0e7a4b962"
}
The secret is shk_ plus 48 hex characters. Only its first 12 characters are stored as prefix, so the console can show you which key is which.
creator_email is the creator's email. A creator who signs in by phone and has no email shows as the phone number with its country code, for example +8613800138000.
secret appears in this one response and is never returned again. Copy it into your secret store before you close the dialog or discard the response body. If you lose it, revoke the key and create another.
Creating a key requires a signed-in session. A key cannot mint another key — that returns 403 ADMIN_REQUIRED.
What a key can do
A key acts as a member of the organization it was created in, regardless of the role of the person who created it.
| Request | With an API key |
|---|---|
GET /v1/offers, GET /v1/offers/summary, GET /v1/offers/{id}, GET /v1/catalog/status | Allowed |
GET /v1/templates, GET /v1/templates/{id}, GET /v1/templates/by-hash/{hash_id}, POST /v1/templates/{id}/duplicate | Allowed |
POST /v1/instances, stop, start, delete, logs | Allowed |
GET /v1/billing/transactions, GET /v1/billing/spend-daily | Allowed |
GET /v1/api-keys | Allowed |
GET /v1/me, GET /v1/ssh-keys, POST /v1/ssh-keys | 401 TOKEN_INVALID — account endpoints need a session |
POST /v1/billing/orders | 403 ADMIN_REQUIRED — a top-up can only be started by an admin in a signed-in session |
Invites and member management under /v1/orgs/current | 403 ADMIN_REQUIRED |
POST /v1/api-keys, DELETE /v1/api-keys/{id} | 403 ADMIN_REQUIRED |
Any request carrying an X-Org-Id for another organization | 403 ORG_MISMATCH |
Two consequences worth planning around:
- A key cannot top up the balance. Once the organization's balance no longer covers one hour of its burn with the instance added, deploys and starts fail with
402 INSUFFICIENT_BALANCEuntil an admin adds credits in the console. See How billing works. - A key cannot add SSH keys. Add yours in the console first, then pass its
ssh_key_idwhen you deploy. Apersonalkey can attach only the SSH keys of the person who created it. Ateamkey acts for the organization: it can attach the SSH key of anyone who is a member now, and of no one who has left — its own creator included. See Add a key.
List keys
curl -s "$SUPERHEAT_API/v1/api-keys" \
-H "Authorization: Bearer $SUPERHEAT_KEY"
Returns {"items": [...]} of the organization's active keys, newest first, each with id, name, kind, prefix, creator_email, creator_id, created_at, last_used_at and creator_is_member. Revoked keys are not listed, and the secret never appears again. last_used_at is updated on every request the key makes, which is the fastest way to find a key nothing is using anymore.
creator_is_member is false once the person who created the key has left the organization, and the API Keys page marks the key creator left. A personal key stops working at that point, so revoke it to tidy up. A team key keeps working — it is the organization's — but whoever left was shown its secret once and may still hold a copy, so the page tells you to revoke it and create a new one.
Revoke a key
curl -s -X DELETE "$SUPERHEAT_API/v1/api-keys/0f5a1c93-6d21-4e7c-a0b8-3c9f2e1d4a77" \
-H "Authorization: Bearer $SESSION_TOKEN"
Returns 204 No Content. The key stops working on the next request it makes. In the console, the trash icon next to a key asks first — Revoke “{name}”?, naming whether it is a personal or a team key — and Revoke key confirms.
| Who | Can revoke |
|---|---|
| Admin | Any key in the organization |
| Member | Only their own personal keys |
| An API key | Nothing — 403 ADMIN_REQUIRED |
Revoking an unknown, already-revoked, or other organization's key returns 404 API_KEY_NOT_FOUND. Revoking does not touch instances the key deployed; they keep running and keep billing until you stop or destroy them.
When a member is removed
When an admin removes a member on the Team page, the personal keys they created in this organization are revoked at once; a personal key also re-checks on every request that its creator is still a member, so they all answer 401 TOKEN_INVALID afterwards. team keys are not affected and keep working after their creator leaves. Instances deployed with any of these keys are not affected either: they keep running and keep billing.
So give automation that must not stop when someone leaves — CI above all — a team key. A team key acts for the organization: deploys through it can attach the SSH key of any current member, and deployed_by names the key rather than a person. It does not stop when its creator leaves, but they were shown its secret once — so when the admin who created one leaves, switch to a team key created by a current admin and revoke the old one. See Roles and permissions.