> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voyager.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloud machines API reference

> Every /v1/machines endpoint: presets, GPUs, images, machines, commands and jobs, files, ports and snapshots, with their fields and error codes.

Base URL `https://api.voyager.so/v1/machines`. Authenticate with `Authorization: Bearer $VOYAGER_API_KEY`, or as `voyager-cloud` does after `voyager-cloud login`. Every endpoint, with full request and response schemas, is also in the generated **API reference** group in the sidebar and in the OpenAPI document at [api.voyager.so/v1/openapi.json](https://api.voyager.so/v1/openapi.json). Every route that takes a machine id (`mch_…`) also takes its name.

| Method and path | What it does |
| - | - |
| `GET /presets` | `{presets: [{id, name, gpu, vram_gib, ray_tracing, image, credits_per_minute, usd_per_minute, for, default}]}` |
| `GET /gpus` | GPUs you can lease: `{gpus: [{gpu, vram_gib, ray_tracing, credits_per_minute, usd_per_minute, default}]}` |
| `GET /images` | `{images: [{id, name, description, default, includes}]}` |
| `POST /` | Lease a machine. Body: `preset` (default `render`), `name`, `gpu`, `image`, `idle_timeout` (seconds, default `900`, `30` to `604800`), `budget_usd`, `from_snapshot`. Send `Idempotency-Key`. Returns the machine, `202`. |
| `GET /` | `{machines, next_cursor}`, newest first. Query: `name`, `status` (comma-separated), `limit` (default 50, max 200), `cursor`. |
| `GET /{id}?wait=N` | The machine: `{id, name, status, gpu, image, preset, created_at, ready_at, idle_timeout, cost: {credits, usd}, error, next}`. `wait` holds up to `N` seconds (max 60) for it to become ready. |
| `POST /{id}/pause` | Pause: stop GPU billing, keep the disk. |
| `POST /{id}/resume` | Resume a paused machine (`202`). |
| `DELETE /{id}` | Release: billing stops and the disk is deleted. Returns the final machine with its `cost`. |
| `POST /{id}/run` | Body `{command` or `argv, cwd, env, timeout, wait}`. With `wait: true`: `{job_id, status, exit_code, stdout, stderr, truncated, resumed, next}` within about 60 s, else the running job (`202`). Without `wait`: the job (`202`). |
| `GET /jobs/{job}?wait=N` | The job: `{id, machine_id, status, exit_code, output_tail, started_at, ended_at, resumed, next}`. |
| `GET /jobs/{job}/logs` | `{text, next_cursor, eof}`. Query: `cursor`; `follow=true` streams plain text until the job ends. |
| `POST /jobs/{job}/cancel` | Stop the job. |
| `POST /{id}/files/upload` | Body `{root, files: [{path, size, sha256, content_base64}]}`. Each file comes back `unchanged`, `written`, or `upload` with an `upload_url` to `PUT` and an `upload_id`. |
| `POST /{id}/files/upload/complete` | Body `{root, files: [{path, sha256, upload_id}]}`. Commits uploaded files; each comes back `written` or `committing`. |
| `POST /{id}/files/download` | Body `{root, paths: [...]}`, files or folders. Each file: `{path, size, sha256}` plus `content_base64` (small) or `download_url` (valid 2 hours). |
| `POST /{id}/ports` | Body `{port}` → `{port, url, expires_at}`; `url` is `https://<id>.run.voyager.computer/`, reachable by anyone with the link. |
| `POST /{id}/snapshots` | Optional body `{name}` → `{id, status, created_at, next}`. Lease from it with `from_snapshot`. |

`root` defaults to `/project`, which is also the default `cwd` for commands. Run and file calls on a paused machine resume it first and say `resumed: true`. Pause, resume, release, run and snapshot accept an `Idempotency-Key`.

## Values

| Field | Values |
| - | - |
| Machine `status` | `starting`, `ready`, `paused`, `released`, `failed` |
| Job `status` | `running`, `succeeded`, `failed`, `canceled` |
| `preset` | `render` (RTX PRO 6000, default), `render-lite` (L4), `compute` (H100, no ray tracing) |
| Ids | machines `mch_…`, jobs `mjb_…`, snapshots `snp_…` |

## Errors

Errors use the API's [error envelope](https://docs.voyager.so/api/errors.md) (`{"error": {"code", "message", "retryable", "details", …}}`). Machine error codes are UPPER\_SNAKE. `429` and `503` responses send `Retry-After`. Retry only when `retryable` is `true`, with the same `Idempotency-Key`.

| Status | Codes | What to do |
| - | - | - |
| `400` | `INVALID_REQUEST` | Fix the request; `message` says what's wrong. |
| `401` | | The key or sign-in is missing or invalid. Sign in again or check `VOYAGER_API_KEY`. |
| `402` | `INSUFFICIENT_CREDITS` | Not enough credits. Show `details.upgrade_url`. |
| `403` | `PLAN_REQUIRED`, `VERIFICATION_REQUIRED` | The workspace needs a paid plan (Starter or above) with a completed payment, or the key lacks a scope. Show `details.upgrade_url`. |
| `404` | `NOT_FOUND` | No such machine, job or path. |
| `409` | `MACHINE_NOT_READY`, `MACHINE_RELEASED` | The machine is in the wrong state: wait until it's `ready`, or lease a new one. Also returned when an `Idempotency-Key` was used for a different request. |
| `429` | | Rate limited: wait `Retry-After` seconds. |
| `500` | `INTERNAL_ERROR` | Retry if `retryable` is `true`. |
| `503` | `UPSTREAM_UNAVAILABLE` | No capacity or a temporary outage: wait `Retry-After` seconds and retry. |

A machine that fails while starting has `status: failed` and an `error` with a `code` and `message`. A failed machine doesn't bill.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.