Skip to main content
POST /v1/instances/{id}/exec runs a shell command inside the instance, straight from your backend. It is the escape hatch for anything the API does not wrap as its own call. The command runs through sh -c as the image’s default user, on the same box the agent works on, so it sees the agent’s files, tools, and credentials.

Request

string
required
The shell command to run inside the instance. It is passed to sh -c, so pipes, redirects, and && chains all work. It must not contain a null byte, which no shell can carry: one returns 400 invalid_request.
A running instance runs the command right away. A sleeping instance is woken first, the same way a request to one of its URLs or an explicit start wakes it, so the first call after a sleep takes about 10 seconds longer in the common case, and a couple of minutes when the wake has to rebuild the instance (it then boots fresh: files on disk are kept, processes and in-memory state are not). The wake can fail the way a start can: 409 try_again means a sleep checkpoint was being written (tens of seconds on a large instance, retry with backoff), 502 provisioning_failed means the wake failed, 409 capacity_unavailable means a rebuild found no host with room, and 402 insufficient_balance means the instance is suspended for non-payment. Exec does not wait for a wake another request started: an instance that is already waking returns 400 invalid_request, as does any other status that is not running or sleeping (a deleted instance returns 404 not_found). If the platform cannot reach the instance at all, you get 502 provisioning_failed. Every exec counts as activity, so an instance you drive only through exec stays up while commands keep coming.

Response

A command that runs but exits nonzero is a normal result: you get 200 with its exit_code, stdout, and stderr. Errors are reserved for the platform, not your command.
integer
The command’s exit code. Nonzero is still a 200; read this to branch.
string
Standard output, capped at 512 KB. See truncated.
string
Standard error, with its own separate 512 KB cap.
boolean
true when either stream spilled past its 512 KB cap. The middle of the output is cut and a truncation marker is left in its place.
exit_code values 125, 126, and 127 may come from the container runtime rather than your command, for example 127 when the binary is not found. The call waits up to 13 minutes (780 seconds) for the command, a wake from sleep included, then fails with 502 provisioning_failed. The command itself is not stopped by that: it keeps running inside the instance, so a blind retry starts a second copy. For longer jobs, start the command in the background with its output sent to a file, nohup ./job.sh > job.log 2>&1 &, and poll with a second exec. The redirect is required: a background command that still writes to the call’s own output holds the call open until it exits.

Example

Build on exec

Anything the API does not wrap as its own endpoint, you build on exec. For moving files, prefer the instance’s own files endpoints at https://{instanceId}.agent37.app (PUT /v1/files/content to upload, GET /v1/files/content to download), but a quick text read works over exec too. A “Download the report” button in your product can be one exec call that reads the file the agent wrote:
curl
Pushing a file in is the same trick in reverse. Encode it on your side and decode it inside the instance:
curl
For binary or large files, use the files endpoints on the instance URL instead, where GET /v1/files/content streams a download of any size with no 512 KB cap, or stage them at a URL your backend controls and curl them down from inside the instance.