> For clean Markdown of any page, append .md to the page URL. For a complete documentation index, see https://ibee.ai/docs/llms.txt (full text of every page: https://ibee.ai/docs/llms-full.txt). For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://ibee.ai/docs/_mcp/server.

# Asynchronous operations

> Which writes return before they finish, how to follow them to a terminal state, and what to do on a timeout.

Most writes finish before they answer. A few return as soon as the work is accepted and give you an
identifier to follow. This page lists every one of them, the read that reports progress, and the states
that mean the work is over.

## The rule

1. Keep the identifier the response gives you (`operation_id`, `restore_id`, or the resource id).
2. Poll the status read until the state is terminal. Every few seconds is enough; honour `Retry-After` on
   a `429`.
3. A terminal state is final. `succeeded` means the resource is in the state you asked for; `failed`,
   `cancelled` and `timed_out` come with an error code and message in the same response.
4. If your client times out before a terminal state, read the status again. Never resubmit the write:
   the first one may still complete, and a second create would make a second billable resource. VM
   writes take an `X-Idempotency-Key` header, so a retry with the same key is safe; a new key is a new
   request.

## Compute operations

Every VM write below answers `202 Accepted` with an [`OperationAccepted`](/docs/api-reference/cloud-vms)
body that carries `operation_id` and `vm_id`. Follow it with
`GET /compute/operations/{operation_id}`.

| Write (cloud and GPU VMs)                                 | States while running                             | Terminal states                                 |
| --------------------------------------------------------- | ------------------------------------------------ | ----------------------------------------------- |
| `POST /compute/cloud-vms`, `POST /compute/gpu-vms`        | `accepted`, `running`, `waiting`, `compensating` | `succeeded`, `failed`, `cancelled`, `timed_out` |
| `DELETE …/{vm_id}`                                        | same                                             | same                                            |
| `POST …/{vm_id}/actions/start`, `…/stop`, `…/reboot`      | same                                             | same                                            |
| `PATCH …/{vm_id}/actions/access`                          | same                                             | same                                            |
| `POST …/{vm_id}/actions/resize`                           | same                                             | same                                            |
| `POST …/{vm_id}/actions/attach-volume`, `…/detach-volume` | same                                             | same                                            |

The operation's `action` names the work (`create`, `start`, `stop`, `reboot`, `delete`, `resize`,
`attach_volume`, `detach_volume`, `update_access`), `current_step` says where it is, and `error_code`
plus `error_message` explain a failure. `compensating` means a failed step is being rolled back; wait
for the terminal state before acting.

The VM itself reports its own `status` on `GET …/{vm_id}` (`pending`, `creating`, `provisioning`,
`configuring`, `running`, `starting`, `stopping`, `stopped`, `rebooting`, `resizing`, `attaching_volume`,
`detaching_volume`, `deleting`, `deleted`, `error`). Use the operation to know when a request is done
and the VM status to know what the VM is doing now.

## Snapshot and backup restores

| Write                                                                | Follow with                                             | Terminal states                    |
| -------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------- |
| `POST /compute/cloud-vm-snapshots/{snapshot_set_id}/actions/restore` | `GET /compute/cloud-vm-snapshots/restores/{restore_id}` | `succeeded`, `failed`, `cancelled` |
| `POST /compute/gpu-vm-snapshots/{snapshot_set_id}/actions/restore`   | `GET /compute/gpu-vm-snapshots/restores/{restore_id}`   | same                               |
| `POST /compute/cloud-vms/{vm_id}/backups/actions/restore`            | `GET /compute/cloud-vm-backups/restores/{restore_id}`   | same                               |
| `POST /compute/gpu-vms/{vm_id}/backups/actions/restore`              | `GET /compute/gpu-vm-backups/restores/{restore_id}`     | same                               |

A restore answers `200` with `restore_id` and `status: queued`; it then moves through `running`. With
`target_mode: new_vm` the response's `target_vm_id` names the VM being built; with `replace` the source
VM is rebuilt in place; with `volume_only` a detached volume is created.

Snapshot create (`POST …/{vm_id}/snapshots`) answers when the snapshot set exists; its `status` on
`GET /compute/cloud-vm-snapshots/{snapshot_set_id}` tells you when it is usable.

## Block storage

| Write                                            | Follow with                                           | Terminal states       |
| ------------------------------------------------ | ----------------------------------------------------- | --------------------- |
| `POST /block-storage/volumes`                    | `GET /block-storage/volumes/{volume_id}/operations`   | `succeeded`, `failed` |
| `POST /block-storage/volumes/{volume_id}/resize` | same                                                  | same                  |
| `DELETE /block-storage/volumes/{volume_id}`      | same (the volume disappears when the delete succeeds) | same                  |

Each volume operation carries `operation` (`create`, `attach`, `detach`, `resize`, `delete`), `status`
(`in-progress`, `succeeded`, `failed`), the `idempotency_key` it was created with, and `error` on
failure. Attach and detach are VM actions and report through the compute operation above.

## Container registry

| Write                                                 | Follow with                                        | States                                                  |
| ----------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------- |
| `POST /container-registry/registries`                 | `GET /container-registry/registries/{registry_id}` | `observed_state`: `PROVISIONING` → `ACTIVE` or `ERROR`  |
| `DELETE /container-registry/registries/{registry_id}` | same                                               | `DELETING` → `DELETED` (or `404`)                       |
| `POST …/{registry_id}/upgrade`                        | `GET …/{registry_id}/package`                      | package operation: `PENDING` → `APPLIED` or `CANCELLED` |
| `POST …/{registry_id}/reconcile`                      | `GET …/{registry_id}`                              | `observed_state` as above                               |

`desired_state` is what you asked for; `observed_state` is what the service has reached. They agree
when `observed_generation` equals `generation`.

## Networking resources

VPCs, subnets, NAT gateways and port-forwarding rules answer with the resource and a `status` field:
`provisioning` while the network is being programmed, `available` when it is ready, `deleting` while
it is removed, and `error` with an `error_message`. Poll the resource's own read
(`GET /networking/vpcs/{vpc_id}` and so on). Load balancers have their own status read,
`GET /networking/load-balancers/{load_balancer_id}/status`.

## Everything else

Object storage, CDN and secret store writes are synchronous: when the response arrives the change is
made. A `423` means the workspace or resource is locked (for example a suspended account or a committed
VM); it is not a transient state, so do not retry it.