ORCHD

API reference

Base URL is your instance's control API (https://api.<your-domain>, or http://127.0.0.1:8080 locally). Every /v1/* endpoint needs a key — see Keys & access — presented as Authorization: Bearer <key> or X-API-Key: <key>.

Roles below: open = no key · any key = a readonly key suffices · admin = admin only (every POST, PUT and DELETE).

Errors are { "error": "…" } with the status codes listed here.

Health

GET /healthzopen

Liveness. The only endpoint that never requires a key.

{ "status": "ok", "auth": true }

Projects

POST /v1/projectsadmin

Create a project and its workloads. Three mutually exclusive ways to say what to create: explicit workloads, a registered template, or a frozen image ("template@version"). An empty body creates one primary database workload. region defaults to the default region.

{
  "name": "acme",                    // optional
  "region": "local",                 // optional
  "template": "acme",                // optional — create from a template
  "image": "acme@v3",                // optional — create from a frozen image
  "delta": { "web/index.html": "…" }, // optional — files overlaid on the base
  "deleted": ["web/old.html"],        // optional — base paths to remove
  "workloads": [                     // optional (default: one primary db workload)
    { "preset": "vite" },
    { "preset": "api" }
  ]
}

Response 201 — the project with its workloads, each carrying state, routes, endpoints, subroutes, resource caps and (for database workloads) anon_key / service_role_key. Workloads start in provisioning; poll or watch events for running.

GET /v1/projectsany key

All projects with their workloads.

GET /v1/projects/{id}any key

One project.

DELETE /v1/projects/{id}admin

Stop and remove the project, every workload, their routes and their on-disk data. 204. Destructive.

POST /v1/projects/{id}/start · /stop · /restartadmin

Lifecycle for every workload in the project.

PUT /v1/projects/{id}/envadmin

Set environment variables on every workload in the project. Reboots them.

{ "env": { "LOG_LEVEL": "debug" } }

Workloads

POST /v1/projects/{id}/workloadsadmin

Add a workload. Use a preset, or set the fields explicitly (explicit wins).

{
  "preset": "vite",          // or omit and set type/image/port
  "type": "rapidnative-dev",
  "name": "web",             // role; also the route suffix
  "image": "rn-vite:dev",
  "port": 8080,              // the port inside the container
  "memory_mb": 512,
  "cpus": 1.0,
  "env": { "NODE_ENV": "development" }
}

GET /v1/workloads/{id}any key

One workload: state, caps, keys, routes, endpoints, last_seen.

DELETE /v1/workloads/{id}admin

Stop and remove the workload, its routes and its data. 204.

POST /v1/workloads/{id}/start · /stop · /restartadmin

Boot, halt or reboot one workload. A stopped workload is not woken by traffic.

PUT /v1/workloads/{id}/envadmin

Replace the workload's environment variables. Reboots it to apply.

POST /v1/workloads/{id}/keepwarmadmin

Toggle always-on. Enabling boots it now and exempts it from scale-to-zero.

{ "enabled": true }   // -> { "keep_warm": true }

GET /v1/workloads/{id}/statsany key

Live memory and CPU. Empty when not running.

{ "mem_usage": "76.2MiB / 384MiB", "mem_perc": "19.8%", "cpu_perc": "1.0%" }

GET /v1/workloads/{id}/logsany key

Recent stdout + stderr. Params: tail=<n> (default 200).

{ "logs": "…last N lines…" }

Workload files

GET/v1/workloads/{id}/fsany key — list files in the workload's tree
GET/v1/workloads/{id}/fs/file?path=…any key — file contents as text/plain
PUT/v1/workloads/{id}/fs/file?path=…admin — write a file (raw body, 16 MiB cap)
DELETE/v1/workloads/{id}/fs/file?path=…admin — delete a file. 204

Routes (domains)

POST /v1/workloads/{id}/routesadmin

Attach a hostname. Point the DNS at the gateway first; a certificate is issued on the first HTTPS request.

{ "host": "app.customer.com" }

DELETE /v1/routes?host=…admin

Detach a hostname. 204.

Templates

GET /v1/templatesany key

Registered templates as { name: path }.

PUT /v1/templatesadmin

Register (or re-point) a template.

{ "name": "acme", "path": "/srv/templates/acme" }

GET /v1/templates/{name}any key

The parsed orchd.json manifest.

GET /v1/templates/{name}/filesany key

File list, or one file's contents with ?path=….

GET /v1/templates/{name}/bundleany key

tar.gz of the template tree, minus derived paths.

POST /v1/templates/{name}/buildadmin

Freeze the template into a new auto-incremented version. Returns 201 with the image record (tarball path, per-workspace docker tags, workload shape). See Images.

Built images

Versioned freezes of a template.

GET/v1/built-imagesany key — list
GET/v1/built-images/{name}/{version}/bundleany key — download the base tarball
POST/v1/built-images/{name}/{version}/pushadmin — re-tag and push to the configured registry → { "registry": { workspace: ref } }
GET/v1/built-images/{name}/{version}/specany key — the self-contained import spec
POST/v1/built-images/importadmin — record an image from another instance (post the spec)
DELETE/v1/built-images/{name}/{version}admin — delete the record and tarball. 204

Docker images

Tags on a region's Docker daemon. Requires the Docker driver; the process driver answers 501. region is optional everywhere (empty = default region).

GET /v1/imagesany key

List, excluding dangling layers. digest is the stable identity to pin against.

[{ "repository": "rn-vite", "tag": "dev", "ref": "rn-vite:dev", "id": "a1b2c3d4e5f6",
   "digest": "sha256:9f86d081…", "size": "412MB", "created_at": "2 days ago" }]

POST /v1/images/pulladmin

Pull a ref. Blocks until the pull finishes and returns the CLI output.

{ "ref": "ghcr.io/acme/app:1.2.0", "region": "" }

DELETE /v1/images?ref=…admin

Remove by ref or id. Fails if a container uses it unless force=true. 204.

Backups

POST /v1/workloads/{id}/backupsadmin

Snapshot one workload now.

{ "id": "wid__20260719T…", "workload_id": "wid", "created_at": "…", "size_bytes": 4797652 }

POST /v1/projects/{id}/backupsadmin

Snapshot every workload in a project. Returns an array.

GET /v1/backupsany key

All backups, newest first.

GET /v1/workloads/{id}/backupsany key

Backups for one workload.

POST /v1/workloads/{id}/restoreadmin

Replace the workload's data with a backup, then reboot it.

{ "backup_id": "wid__20260719T…" }   // -> { "status": "restored" }

DELETE /v1/backups/{id}admin

Delete a backup. 204.

POST /v1/system/backupadmin

Snapshot the control-plane state off-box under the reserved key _control-plane. Runs on the backup schedule too.

Regions

GET /v1/regionsany key

[{ "id": "local", "name": "local", "docker_host": "", "is_default": true, "created_at": "…" }]

POST /v1/regionsadmin

Create one; the id is a slug of the name.

{ "name": "EU West", "docker_host": "tcp://node2:2375" }

DELETE /v1/regions/{id}admin

Delete (never the default — set another first). 204.

POST /v1/regions/{id}/defaultadmin

Make it the default. → { "default": "eu-west" }

API keys

GET /v1/keysany key

Metadata only, never secrets.

POST /v1/keysadmin

Mint a key; the plaintext is returned exactly once.

{ "name": "ci-bot", "role": "readonly" }

DELETE /v1/keys/{id}admin

Revoke. 204.

Settings

Runtime configuration. Secrets are stored server-side and never returned.

GET /v1/settingsany key

{
  "instance_name": "acme cloud",
  "backup": { "type": "s3", "endpoint": "…", "bucket": "…", "region": "…", "access_key": "…" },
  "backup_secret_set": true,
  "webhook": { "url": "" },
  "metrics": { "type": "nop" },
  "registry": "ghcr.io/acme"
}

PUT /v1/settings/nameadmin

Name this deployment (shown in the panel). { "instance_name": "acme cloud" }

PUT /v1/settings/registryadmin

The registry prefix built images are pushed under. { "registry": "ghcr.io/acme" }

PUT /v1/settings/backupadmin

The backup destination. Leave secret_key blank on an s3 target to keep the existing secret.

{
  "type": "s3",                 // "local" | "s3"
  "endpoint": "https://<account>.r2.cloudflarestorage.com",
  "bucket": "backups", "region": "auto", "prefix": "backups",
  "access_key": "…", "secret_key": "…"
}

PUT /v1/settings/webhookadmin

Event webhook URL; blank disables it. { "url": "https://example.com/hooks" }

PUT /v1/settings/metricsadmin

Metrics sink. { "type": "http", "url": "https://collector/metrics" }type is nop, log or http.

Metrics, events, metadata

GET /v1/metricsany key

Live fleet snapshot.

{ "time": "…", "projects": 3, "workloads": 6, "running": 2, "suspended": 4,
  "mem_mb_allocated": 768 }

GET /v1/eventsany key

Recent control-plane events, newest first. Params: limit=<n> (default 100).

[{ "id": "…", "time": "…", "type": "project.created", "project_id": "abc123", "message": "" }]

GET /v1/presetsany key

Preset names available on this instance.

GET /v1/infoany key

What this instance is running — the fastest way to confirm a deployment.

{
  "instance_name": "acme cloud",
  "driver": "docker+runsc", "region": "local", "base_domain": "example.com",
  "public_url": "https://example.com",
  "idle_timeout": "5m0s", "image": "tinbase:0.10.0", "rate_limit_per_min": 600,
  "limits": { "tinbase_mem_mb": 384, "tinbase_cpus": 0.5,
              "dev_mem_mb": 512, "dev_cpus": 1, "pids_limit": 512 },
  "backups": { "enabled": true, "interval": "24h0m0s", "retain": 7 },
  "images_supported": true,
  "metrics": { "type": "nop" },
  "presets": ["api", "expo", "tinbase", "vite"]
}

Internal

GET /internal/tls-allow?domain=…open

Caddy's on-demand-TLS gate: 200 for admin/api on a configured base domain and for any host in the route table, 403 otherwise. Not for general clients — see Routing & TLS.

from the same team

Related projects

ORCHD is built by the makers of these open-source tools and products.