Getting started
Operations and retries
Changes are saved first and finish shortly after. Follow a change's operation, and retry safely with an Idempotency-Key.
Operations
When you create, start, stop, rename or snapshot a Computer, Heaven saves the change, and the Computer's server carries it out shortly after. The response is an operation you can follow. Closing the connection never cancels it.
| State | Means |
|---|---|
accepted | Heaven saved it, and the server is working on it. |
complete | It's done. |
failed | It couldn't be done. error_code says why, and message says what to do next. |
superseded | A newer change replaced it before it finished, such as a stop sent during a restart. |
accepted doesn't mean the Computer is ready. It's ready when its own state is running.
Read an operation
GET/v1/operation/
Returns an operation's progress. With wait, it returns the outcome once the operation finishes or the wait ends.
You can read any operation you started, even after its Computer is renamed or deleted. If the wait ends before the operation does, the response is unknown with the operation's ID. That means it hasn't finished yet, not that it failed, so ask again.
Query
operationstring requiredThe operation's ID, as the change returned it.
waitbooleanWait until it finishes, up to
timeout.timeoutstringHow long
waitwaits: 10s by default, up to 10m.
- An API key needs
operation viewin its commands.
curl 'https://heaven.dev/v1/operation/?operation=8540e6f2-9f39-4d39-89b5-eeac80d0ac97&wait=true' \
-H "Authorization: Bearer $HEAVEN_API_KEY"{
"version": 1,
"data": {
"operation": {
"id": "8540e6f2-9f39-4d39-89b5-eeac80d0ac97",
"kind": "create",
"computer_id": "0098166a-9908-43ab-967b-4111c45c3b33",
"revision": 1,
"state": "complete",
"created_at": "2026-11-01T23:19:37Z",
"completed_at": "2026-11-01T23:20:11Z"
}
}
}{
"version": 1,
"error": {
"kind": "unknown",
"message": "The operation is still in progress. Check again with `operation view 8540e6f2-…`.",
"operation_id": "8540e6f2-9f39-4d39-89b5-eeac80d0ac97"
}
}Operation groups
Some changes act on several Computers at once: a pool snapshot, a pool split or combine, a pool copy, and deleting your account. Each returns one operation group that holds each Computer's operation. Read it with the same GET /v1/operation/, and wait works too.
A group's state is accepted until every operation in it finishes. Then it's complete, or failed if any operation failed or was superseded.
{
"version": 1,
"data": {
"operation": {
"id": "4baa2b68-1bd1-4cd2-b965-c9eb9513de73",
"kind": "pool snapshot create",
"state": "accepted",
"pool_id": "pool-a84a2847cd584a0c",
"subject": "nightly",
"operations": [
{
"id": "66778689-c39f-403e-a841-a8c445fd5bf0",
"kind": "snapshot",
"computer_id": "317ff25b-84a8-4112-815e-d79f0ff6d5b0",
"revision": 2,
"state": "accepted",
"created_at": "2026-11-02T13:15:16Z"
},
…
],
"created_at": "2026-11-02T13:15:16Z"
}
}
}Streaming a change
Send a change with Accept: application/x-ndjson to get its progress as it happens, one JSON object per line. The first line is accepted. An operation line follows as each operation finishes, and complete comes last. If 25 seconds pass before then, the last line is pending, with the operations to read later.
A change that names several Computers in computers (except a delete), or a change to a whole pool, returns its usual JSON instead.
curl https://heaven.dev/v1/computer/modify \
-H "Authorization: Bearer $HEAVEN_API_KEY" \
-H "Accept: application/x-ndjson" \
--json '{"computer":"my-site","action":"restart"}'{"version":1,"event":"accepted","data":{"request_id":"…","operation":{"id":"7bbd53b7-…","kind":"restart","state":"accepted"}}}
{"version":1,"event":"operation","data":{"operation":{"id":"7bbd53b7-…","kind":"restart","state":"complete"}}}
{"version":1,"event":"complete","data":{"operations":[{"id":"7bbd53b7-…","state":"complete"}]}}Retrying safely
A network error can lose the response after the change was saved. To retry such a change safely, send an Idempotency-Key header: any string of 1 to 128 bytes that you choose. It matters most for a change that creates something or spends money. Sending the same request again with the same key returns the first response, and never makes a second Computer, operation or purchase. The heaven program sends one for you.
curl https://heaven.dev/v1/computer/create \
-H "Authorization: Bearer $HEAVEN_API_KEY" \
-H "Idempotency-Key: create-my-site" \
--json '{"name":"my-site","pool":"web"}'- Choose the key before the first attempt, and keep it with the request. Heaven makes one when you leave it out, but you can't recover that one from a lost response.
- The same key with a different request is refused (
conflict), so a typo never acts on the wrong thing. - Idempotency keys belong to you, not to an API key. A retry with another of your API keys returns the same response.
| Retry | Commands |
|---|---|
With Idempotency-Key | create, delete, rename, move, resize, reset, tag, comment, start, stop, restart, pause, resume, every snapshot change, pool create, pool split, pool combine, pool snapshot create, restore and delete, capacity buy, billing charge, ip buy, feedback |
| Send it again | Everything else that changes something. It sets the same state again, or returns conflict or not_found because it's already done. |
| Check first | api-key create and share link add make a second key or link. organization create, organization team create and integration create return conflict because the name is taken. |
| Never repeated | exec with a command. After a lost response the outcome is unknown, so check inside the Computer. |
A command that doesn't take an Idempotency-Key refuses one (invalid) rather than ignoring it.
When the outcome is unknown
An unknown error (HTTP 503) means Heaven couldn't confirm what happened: the change may or may not have been saved. It never means the change failed. To find out, read the operation if the error names one, or send the same request with the same Idempotency-Key. Either tells you what happened without doing it twice.