Skip to main content
An instance is a persistent, isolated computer running your agent. Create one per end user. The call is synchronous: when status is running, the instance’s computer is up and the agent inside finishes booting moments later. Poll GET /v1/health on the instance URL until it answers "healthy": true (ok alone only means the gateway is up; see Health & version), then message it at https://{id}.agent37.app/v1/responses (see Send a message and Instance and preview URLs). Creating an instance requires one day of compute at its running rate in your workspace wallet, but debits nothing: the balance check is the create gate (below it, the create fails with 402 insufficient_balance and nothing is provisioned), and the meter only starts when the instance first reaches running. How many instances you can run at once is set by your instance limit, which rises as you top up. See Billing.

Create an instance

POST /v1/instances returns 201 with the full instance object once status is running. Every field is optional, so a POST with no body works: you get the default template (agent37-hermes) on the smallest shape, 2 vCPU / 4 GB.
string
default:"agent37-hermes"
A template name. agent37-hermes (full Hermes, with browser and desktop) is the default; agent37-hermes-small (the same agent on a lean image, no browser or desktop), agent37-openclaw (OpenClaw, with a headless browser), agent37-claude-code (Claude Code, which needs your own Anthropic account connected before chat turns work), agent37-codex (Codex, which needs your own OpenAI account connected before chat turns work), agent37-grok (Grok, which needs your own xAI API key set before chat turns work), agent37-opencode (OpenCode, which runs on the managed model out of the box), and agent37-n8n (n8n, a workflow automation web app with no chat API; its editor gets a public URL on create) are the other system templates. You can also pass one of your own workspace templates by name. Any name takes an optional @<version> to pin a published release: a tag on system templates (agent37-hermes@2026.07.02b), a revision number on workspace templates (my-agent@2). Pin when your creates must be reproducible; the bare name follows the latest release. Unknown names and unpublished versions return 400 invalid_request. Direct image references are rejected with 400: register a template first, then pass its name.
object
The instance shape, for example { "cpu": 2, "memory": 4, "disk": 6 }. Omitted, it uses the smallest shape, 2 vCPU / 4 GB. Every template offers the same three shapes below. Free workspaces (before your first top-up) run the 2 vCPU / 4 GB shape; the larger 4/8 and 8/16 shapes return 403 tier_limit until you top up. Disk is any whole number of GB within the shape’s range, and defaults to 4, 6, or 12 GB by shape when omitted. Any other combination returns 400 invalid_request listing the valid shapes.
string
default:"default"
default is what every create uses, and for most harnesses it is all you need. performance runs the instance on dedicated cores, for heavy work such as computer use, and is enabled per workspace: until yours is, create returns 403 performance_unavailable with a link to set it up. Start with the default. See Default and Performance instances.
string
An opaque tag for your own attribution, typically your end user’s id. Stored, never interpreted, echoed back on the instance object.
string
A label for the instance.
object
Your own key/value pairs. Stored, never interpreted.
object
Environment variables for the container, as string key/value pairs. Set once at create and replayed on every restart, update, and wake. Up to 64 entries and 64 KB in total; keys are uppercase letters, digits, and underscores starting with a letter; values are strings of up to 4096 characters. See Environment variables.
object
Caps on this instance’s managed usage (managed LLM, Brave search, and Composio calls), in micros (millionths of a dollar): monthly_cap_micros resets each UTC month, credit_micros adds one-time headroom that persists until spent. Both default to 0, so managed calls are refused until you raise one. These are ceilings, not money; spend still draws the workspace wallet. See Budgets.
boolean
default:"false"
Opt the instance into auto-sleep: once no bytes have moved through its URLs for idle_timeout_seconds, it is checkpointed to sleeping and bills disk alone until a request wakes it. Awake minutes bill the ordinary compute rate.
integer
default:"900"
How long the instance must be idle before it sleeps, in seconds. An integer from 300 to 86400 (five minutes to one day). Only meaningful with auto_sleep: true.
object[]
Ports to expose at permanent unauthenticated URLs, each { port, prefix? }, for webhooks and other callers that can’t send a credential. See Public ports, or follow the end-to-end Hermes webhook setup for port 8644.

Shapes and pricing

Disk bills at $0.09 per GB per month, included in the prices above at the default disk. Those are the prices of the default instance type. The monthly price is the rate; the wallet is metered per minute, and only for what the instance holds: running time bills the full rate, and stopped or sleeping time bills the disk alone. Deleting an instance settles its final minutes and billing ends. See Billing.

Example

The credit_micros of 1000000 gives the instance $1 of managed-spend headroom so its first chat works out of the box.

Environment variables

env puts your own variables in the container. They are stored with the instance and reapplied every time the container is rebuilt, so a restart, an update, or a wake from sleep keeps them.
Your variables layer over the managed services the platform injects, so the three names above are how you point a catalog agent at your own OpenAI-compatible provider instead of the managed one. Any endpoint works, OpenRouter included; the URL is normalized to end in /v1. Spend then goes to that provider, not your Agent37 wallet, and the instance’s budget no longer applies to model calls. For a fuller setup with your own per-user metering, see Bring your own model. Six names are set by the platform and rejected with 400 invalid_request rather than silently ignored, because they tell the image which instance it is: AGENT37_INSTANCE_ID, AGENT37_RUNTIME_IMAGE_REF, AGENT37_AGENT_TYPE, AGENT37_GATEWAY_PORT, OPENCLAW_GATEWAY_PORT, and OPENCLAW_CONTROL_UI_INSTANCE_ORIGIN. env is write-only: it is not returned by GET /v1/instances/{id}, and it cannot be edited after create. To change a variable, create a new instance.

The instance object

string
A bare 10-character lowercase alphanumeric id, no prefix. It doubles as the DNS label in the instance’s URL.
string
The lifecycle state. running means the instance’s computer is up; poll GET /v1/health before the first message. Around a wake or a start the field can trail reality by a few seconds: the response to your own request, or the instance’s health endpoint, is the authority. See the statuses table below.
object | null
Why the most recent lifecycle operation failed, as { code, message, detail?, operation, at }, or null when there is no failure reason. detail, when present, carries the raw failure output, including the tail of your container’s console log when the container exited or never opened its port during a create; use it to see your own application’s startup error. at is an epoch-second timestamp.
string
The template the instance was built from, including its version pin when it has one (agent37-hermes@2026.07.02b, my-agent@2).
integer | null
The workspace template revision this instance has installed. Compare it with the template’s current revision to detect an available update. It changes only when the instance is created or updated, and is null for system templates and for instances created before revisions existed (an update stamps it).
string | null
The public source reference for a system template or registry-born workspace template. null for an image published by a cloud build. This never exposes Agent37’s internal private-mirror path.
string | null
The immutable sha256:... digest of the image the instance runs. Use this, not a mutable image_ref tag, as the exact image identity. null only on older instances that predate digest pinning.
object
The shape: cpu (vCPUs), memory and disk (GB).
string
The bare instance URL, https://{instanceId}.agent37.app, where the agent’s chat API lives (it routes to the template’s default_port, 3737 unless declared otherwise). Every other port is reachable at https://{instanceId}-{port}.agent37.app, derivable with no declaration needed. Open any port in a browser with a signed URL. See Instance and preview URLs.
string[]
The instance URL mirrored under each of your workspace’s active custom domains; empty until a domain is active.
object[]
The instance’s public ports, each { port, url, domain_urls, prefix, created }: permanent unauthenticated URLs, empty unless you created some.
string | null
Your attribution tag, echoed back.
string | null
Your label, echoed back.
object | null
Your key/value pairs, echoed back.
boolean
Whether the instance sleeps on idle. Set at create or by PATCH. See Auto-sleep.
integer
How long the instance must be idle before it sleeps, in seconds. Defaults to 900.
integer | null
Present only while status is sleeping or waking: when the instance fell asleep, in epoch seconds. It does not signal that the checkpoint has finished: status flips to sleeping before the checkpoint is written, and during the write this field can be null or still carry an earlier timestamp. Instances that have been asleep for a long stretch may be rebuilt from cold storage on wake, which takes about two minutes (see Auto-sleep).
boolean
true when the workspace balance went negative and the instance was suspended. Top up to clear it; the next request to the instance’s URL wakes it. See Billing.
integer
Creation time in epoch seconds.

Endpoints

List, get, delete

GET /v1/instances returns { "data": [ ... ] }, newest first, each element the full instance object. GET /v1/instances/{id} returns one. Unknown, deleted, or other-workspace ids uniformly return 404 not_found. DELETE /v1/instances/{id} returns { "id": "ab12cd34ef", "deleted": true }. It acts once: a repeat delete returns 404. Delete settles the final metered window and billing ends; nothing is ever prepaid, so there is nothing to refund.
curl
Delete is destructive: the instance’s files, memory, sessions, and backups are gone. A backup belongs to the instance, not to your workspace, and restore only ever writes back in place, so download anything you want to keep first. To pause work while keeping everything, stop it instead. A stopped instance bills its disk alone; delete is what ends billing entirely.

Edit name, metadata, and auto-sleep

PATCH /v1/instances/{id} edits the instance’s name, user tag, and metadata after creation, plus its auto-sleep settings. These are the same fields you can set at create, and they are the only things this call changes: it never touches the running container. It returns 200 with the full instance object, the same shape as GET. The patch is partial: only the keys you send change, the rest are left alone. Send a string to set a label field, or null (or "") to clear it. You must send at least one of name, user, metadata, auto_sleep, or idle_timeout_seconds; an empty body returns 400 invalid_request.
string | null
A label for the instance, up to 60 characters. null or "" clears it.
string | null
Your attribution tag, up to 200 characters. null or "" clears it.
object | null
Your key/value pairs, up to 4 KB serialized. The object replaces the stored one, it is not merged. null or {} clears it.
boolean
Turn auto-sleep on or off. Takes effect within about half a minute, with no restart and no recreate.
integer
The new idle timeout: an integer from 300 to 86400 seconds.
Edits never bill and never recreate the container, and they work in any state except deleted. Unknown, deleted, or other-workspace ids return 404 not_found.

Lifecycle

Five calls control whether the instance’s computer is running, which image it runs, and how big it is. Each is a POST to a subpath; stop, start, and restart take no body, update takes an optional template version, and resize takes the new size. They acknowledge the new state only, returning { id, status } (update adds nullable image_ref, image_digest, and template_revision; resize adds resources); GET the instance for its full representation. start and resize answer 202 instead of 200 when they moved the instance to another host and the move is still finishing (status still starting/updating); poll GET until it reads running. The whole disk persists, like a VM. Files anywhere on the filesystem, installed packages, edited config, connected accounts: all of it survives stop, start, restart, and resize, and rides along if the platform ever moves the instance between hosts. The one exception is update, which resets the operating system layer to the fresh image while keeping your data (/home/node and /home/linuxbrew). Writes outside those two directories share a 10 GB operating-system layer separate from the instance’s billed disk. In-memory state is lost whenever the container is recreated; anything that must outlive a restart belongs in a file.

Stop

POST /v1/instances/{id}/stop halts the container. The agent stops doing work (no cron, no heartbeats, no responses) and status becomes stopped. The data stays intact, CPU and memory are released back to the host, and the disk stays reserved on that host. Stop also works on a sleeping instance, and the difference is intent: a sleeper wakes on any request, a stopped instance stays down until an explicit start. Stopping a sleeper discards its checkpoint (the data stays) and its URLs stop waking it. There are two exceptions. While the sleep checkpoint is being written, stop returns 409 try_again; the window is tens of seconds on a large instance, so retry with backoff. A sleeper that has been moved to cold storage after a long idle stretch cannot be stopped: stop returns 400 invalid_request saying the instance is parked in cold storage. Wake it first, with start or any request to its URL, or delete it. Stopping an already stopped instance returns the same ack again; any other state returns 400.
curl

Start

POST /v1/instances/{id}/start brings a stopped instance back up, recreating the container from the image it already ran. It normally returns to its host in seconds; if that host no longer has room for the instance’s CPU and memory, the platform moves the instance to one that does, which takes about a couple of minutes per 10 GB of data. A move that runs longer than the request returns 202 with the instance still starting, and the platform finishes it on its own: poll GET /v1/instances/{id} until it reads running. Only when no host has room at all does it return 409 capacity_unavailable, changing nothing. If the instance is past_due (suspended for non-payment), start returns 402 insufficient_balance until the workspace is funded; topping up clears the flag on its own, and start (or any request to the instance’s URLs) then boots it fresh. Starting an already running instance returns the same ack again. Start also wakes a sleeping instance, with the same effect as a request to one of its URLs, and returns in 5 to 15 seconds in the common case. For a private sandbox with no ports there is no URL to request, so start is its only wake path. It is also the explicit way back for a sleeper that has been moved to cold storage: that wake takes about two minutes and boots the instance fresh (files kept, processes and in-memory state gone). While the sleep checkpoint is being written it returns 409 try_again; the window is tens of seconds on a large instance, so retry with backoff.
curl

Restart

POST /v1/instances/{id}/restart recreates the container from the image already on the host (no download) and returns it to running. Use it to recover a wedged agent or pick up changed settings. Same image, same data. On agent37-hermes it is also how a Hermes profile switch takes effect: run hermes profile use <name> in the instance (over exec or the terminal), then restart; the instance boots its gateway, dashboard, and chat API in that profile’s home, and hermes profile use default plus a restart switches back. The instance must be running; use start to bring a stopped one back up. Concurrent restarts of the same instance do not stack: one proceeds and the rest return 409 try_again. A restart that fails returns 502 provisioning_failed and leaves the instance running when its container is still up or its host could not be reached, with the reason in status_reason, so you can simply retry; it reads failed only when the container is confirmed down.
curl

Update

POST /v1/instances/{id}/update pulls the template’s image, resets the operating system layer to it, and preserves the data in /home/node and /home/linuxbrew. It is the one lifecycle call that discards changes outside those directories, which also makes it the clean-slate repair tool: use it to move an instance onto a newer version after a release (or after you point a workspace template at a new tag), or to recover a failed/stuck instance (read its logs first to see why it failed). A running or recoverable non-stopped instance is recreated and returns running; a stopped instance pulls the image pointer now and stays stopped, then uses that image the next time it starts. The body is optional. Without one, update re-resolves the instance’s stored template: a workspace instance installs the template’s current image and revision, an unpinned system instance moves to the template’s current image, and a version-pinned instance stays on its pin. The one accepted field, template, takes any template name: the same template with an @<version>, a published tag on a system template or a published revision number on a workspace template, pins that release (this works on an unpinned instance too, and pinning an earlier workspace revision is the rollback), the bare name clears the pin to follow latest, and a different template migrates the instance onto it. A template migration keeps the instance’s id, URLs, public ports, and data, and the recreated container adopts the new template’s image, default port, and agent type; the instance keeps its shape, which every template offers. Any other field returns 400. The ack carries the resulting status, the applied template when one was passed, image_ref, image_digest, and template_revision. A sleeping instance cannot be updated: wake it first, with any request to its URL or an explicit start. A bad image reference on the template surfaces here as a 502 provisioning_failed.
curl

Resize

POST /v1/instances/{id}/resize grows a running instance to a bigger size. The body uses the same vocabulary as create’s resources, and omitted fields keep their current value, so { "disk": 10 } grows disk alone and { "cpu": 4, "memory": 8 } moves up a shape (disk carries over unchanged). Resize only grows: any request that would shrink a dimension returns 400, and moving to a smaller size means creating a new instance. The ack carries the new resources, and the meter bills at the new rate from the moment of the resize (see Billing). When its current host has room, the container is recreated in place with the new limits, like restart: the disk, instance id, and URLs are kept, in-memory state is lost, and the instance is back in seconds. When the host cannot fit the increase, the platform moves the instance to one that can: it stops, its data is copied over, and it boots on the new host, so it is down for the copy (about a couple of minutes per 10 GB) and no writes are lost. A move that runs longer than the request returns 202 with the instance still updating, and the platform finishes it on its own: poll GET /v1/instances/{id} until it reads running. Only when no host has room at all does it return 409 capacity_unavailable, changing nothing.
curl

Backups

Every instance’s data (/home/node and /home/linuxbrew) is backed up nightly into seven rotating slots, so the last seven nights are available as restore points. You can also take a backup on demand, into a separate slot that only your next on-demand backup replaces. A new instance has none until its first nightly pass, so take one on demand if you need a restore point before then. Backups and restores are free.

List backups

GET /v1/instances/{id}/backups returns every restore point, newest first: up to seven automatic backups and one manual.
curl
A backup’s id names that one copy. When a slot is overwritten, by the nightly rotation or by your next on-demand backup, its old id leaves the list and a restore of it returns 404 not_found. created is when the backup was taken (unix seconds); size_bytes is the compressed size. Backups of a tree that has not changed hold the same bytes, so they share one id and list once: an idle or stopped instance can show a single record after seven nights.

Back up now

POST /v1/instances/{id}/backups (no body) backs the instance up now and returns the record with 201. The backup is taken live, without pausing the instance, so like the nightly ones it is crash-consistent: a database mid-write may need its own recovery when restored. The call returns when the backup finishes, minutes on a multi-GB instance, and a client that gives up does not cancel it: the backup lands and shows up in the list. One on-demand backup per instance every 15 minutes; a second call inside the window returns 429 rate_limited with a Retry-After header. The window opens on the attempt, not on the result, so a failed backup still holds it, leaving your previous on-demand backup in place. Running, stopped and sleeping instances can be backed up; one parked in cold storage after a long idle stretch returns 400 invalid_request until you start it, since its data already sits in backup storage. A backup is never refused for being smaller than the last one. If you empty the instance by mistake, restore one of the earlier nights from the list; the rotation gives you a week.
curl

Restore

POST /v1/instances/{id}/restore with { "backup": "<id>" } rolls the instance back to that backup, in place: same id, URLs, and public ports. The data is replaced, not merged, so files written after the backup are gone. The container is recreated, so in-memory state is lost; a running instance comes back running, a stopped one stays stopped, and the instance reads updating in between. The operating-system layer comes back as it was at the backup when the instance still runs the same image, and fresh after an update, as update itself leaves it. Restore is destructive and takes no safety copy: back up first if you may want the current state back. backup is the only accepted field; any other returns 400. The instance must be running or stopped: a sleeping one has to be woken first, one parked in cold storage started first, and anything mid-transition or failed returns 400. The call returns when the copy is done, up to 12 minutes. A client timeout does not stop it: the instance stays updating and a second restore returns 400 until the first finishes, so poll GET /v1/instances/{id} instead of retrying. A restore that fails returns 502 provisioning_failed and leaves the instance stopped, or running if it never took the container down, with the reason in status_reason. Every backup is still there, so you can try again.
curl

Auto-sleep

An instance with auto_sleep: true does not have to be up to be available. Once no bytes have moved through any of its URLs for idle_timeout_seconds (default 900, from five minutes to a day), the platform checkpoints it and status becomes sleeping: CPU and memory are released, the disk stays reserved, and billing drops to the disk rate alone (see Billing). The status flips at the start of the checkpoint, not the end; writing it takes tens of seconds on a large instance, and stop, start, and exec return 409 try_again until it is done. Activity is data flow in either direction on any of the instance’s URLs, or a command run through exec; a connection that is open but silent does not count, and API reads like GET /v1/instances/{id} never reset the timer. Sleeping carries no price premium: awake minutes bill the ordinary compute rate, the same as an always-on instance, and asleep time bills disk alone. A mostly-idle instance therefore costs a fraction of the always-on price: a 2 vCPU / 4 GB instance awake an hour a day costs about $0.54 per month, versus $4.76 always-on. It is worth turning on for anything that is idle most of the day. Waking is transparent. Any request to any of the instance’s URLs wakes it: the request is held while the instance restores, then forwarded. The restore itself takes a few seconds. An explicit POST /v1/instances/{id}/start or a command sent through exec wakes it too, returning in 5 to 15 seconds in the common case; for a private sandbox with no ports, which receives no requests, those are the only wake paths. If the checkpoint cannot be restored, or the instance was moved to another host or to cold storage after a long idle stretch, the wake rebuilds the instance instead: it takes about two minutes and boots fresh, so processes and in-memory state from before the sleep are gone while files on disk are kept. A wake that boots fresh returns running while the agent inside is still starting; poll GET /v1/health for "healthy": true before sending work. In-memory state usually survives a wake, but it is not guaranteed: treat anything that must outlive a sleep as a file. While asleep:
  • The instance object reports status: "sleeping" from the moment the checkpoint starts, and slept_at, for example "slept_at": 1781222400.
  • Signed URLs can still be minted, and opening one is exactly the kind of request that wakes the instance.
  • stop works, and means “stay down until I start” (see Stop). While the checkpoint is being written it returns 409 try_again, for tens of seconds on a large instance; retry with backoff. A sleeper already moved to cold storage returns 400 invalid_request (parked in cold storage): wake it with start or any request to its URL, or delete it.
  • restart, update, resize, and restore return 400: wake the instance first, with any request to its URL or an explicit start.
Both fields are set at create and editable any time with PATCH /v1/instances/{id}, no restart needed. Instances default to auto_sleep: false and never sleep unless you opt them in.

Statuses

past_due is a flag, not a status: a suspended instance shows it alongside sleeping (or stopped, if it already was). Top up the wallet to clear it; see Billing.

Capacity and limit errors

See Errors for the full catalog and the error envelope.