Exec Runs API

Dispatch commands to a connected remote and read their output. Each exec run is a stored record. Output is stored separately as sequenced chunks.

Requires API key scopes remotes:read (list, get, read output) and remotes:write (dispatch, signal). Create keys in Settings → API Keys.

Remotes API · Remotes guide


Overview

An exec run is one command executed on a remote. The API creates the run, asks the remote daemon to start the process over the WebSocket, and stores stdout/stderr as sequenced chunks.

ConcernDetail
DispatchPOST /remotes/{id}/execs
StatusPoll GET /execs/{id}
OutputPoll GET /execs/{id}/output?after_seq=N
CancelPOST /execs/{id}/signal
Resume cursorlast_seq on the run. Pass it as after_seq when reconnecting.

The remote must be connected and have exec_enabled: true (start it with belt remote --exec).


Dispatch exec run

POST /remotes/{remote_id}/execs

Starts a command on a remote the caller owns. Requires remotes:write.

Request

FieldTypeRequiredDescription
commandstringYesProgram to run (for example bash, ls)
argsstring[]NoArguments passed to the command
cwdstringNoWorking directory on the remote
envstring[]NoExtra environment variables (KEY=value)
ptybooleanNoRun under a pseudo-terminal
timeout_msintegerNoTimeout in milliseconds (0 = no limit)
json
1{2  "command": "bash",3  "args": ["-c", "echo hello && uname -a"],4  "cwd": "/home/dev/project",5  "timeout_ms": 600006}
bash
1curl -X POST https://api.inference.sh/remotes/remote_abc123/execs \2  -H "Authorization: Bearer inf_your_key" \3  -H "Content-Type: application/json" \4  -d '{"command":"ls","args":["-la"]}'

Response

Returns an ExecRunDTO. The run is already running when dispatch succeeds.

FieldTypeDescription
idstringExec run ID
remote_idstringTarget remote
commandstringProgram
argsstring[]Arguments
cwdstringWorking directory
envstring[]Extra environment
ptybooleanPseudo-terminal flag
timeout_msintegerRequested timeout
statusstringLifecycle state (see status values)
exit_codeintegerProcess exit code. Omitted until the process exits.
errorstringError message. Omitted when empty.
timed_outbooleantrue when killed by timeout
started_atstringISO timestamp when execution began. Omitted until set.
ended_atstringISO timestamp when the run finished. Omitted until set.
duration_msintegerRun duration. Omitted until the run finishes.
requested_bystringWho initiated the run: user, loop, or agent. This endpoint always records user.
agent_run_idstringAgent run the command belongs to, for agent-initiated runs. Omitted otherwise.
last_seqintegerHighest output sequence number stored. Use it as the resume cursor.

Errors

CodeHTTPWhen
invalid_request400command is empty or the body is not valid JSON
exec_disabled403Remote has not opted in (exec_enabled: false)
remote_offline409Remote is not connected

Get exec run

GET /execs/{id}

Returns a single exec run. Requires remotes:read.

bash
1curl https://api.inference.sh/execs/exec_abc123 \2  -H "Authorization: Bearer inf_your_key"

Poll this endpoint until status is terminal (exited, killed, or denied).


List exec runs

GET /execs or POST /execs/list

Cursor-paginated list. Requires remotes:read. See REST overview: cursor pagination.


Read output

GET /execs/{id}/output?after_seq={n}

Returns output chunks with seq greater than after_seq, in ascending order. Requires remotes:read.

QueryTypeDescription
after_seqintegerReturn chunks after this sequence (default 0, from the start)

Each item is an ExecRunOutputDTO:

FieldTypeDescription
idstringChunk ID
created_atstringISO timestamp when the chunk was stored
exec_run_idstringParent exec run
seqintegerSequence number within the run
streamstringstdout or stderr
datastringOutput bytes as a base64 string. Decode it to get the raw output.
json
1{2  "id": "out_abc123",3  "created_at": "2026-01-01T12:00:00Z",4  "exec_run_id": "exec_abc123",5  "seq": 1,6  "stream": "stdout",7  "data": "aGVsbG8K"8}

A request returns at most 2000 chunks.

Resume after disconnect

  1. Read last_seq from GET /execs/{id}, or track the highest seq you have processed.
  2. Call GET /execs/{id}/output?after_seq={seq} to fetch only newer chunks.
  3. Repeat until the run reaches a terminal status.

last_seq only moves forward. A late or duplicate frame with a lower seq does not rewind it.

bash
1# Fetch chunks after sequence 422curl "https://api.inference.sh/execs/exec_abc123/output?after_seq=42" \3  -H "Authorization: Bearer inf_your_key"

Signal (cancel)

POST /execs/{id}/signal

Asks the remote daemon to kill a running exec. Requires remotes:write.

bash
1curl -X POST https://api.inference.sh/execs/exec_abc123/signal \2  -H "Authorization: Bearer inf_your_key"
json
1{2  "ok": true3}

The response is a bare JSON object without the standard envelope. The call does nothing when the run is already terminal.


Exec run status values

StatusTerminalDescription
pendingNoCreated, not yet sent to the host
runningNoSent to the host
exitedYesProcess ended. exit_code is set.
killedYesEnded without an exit code: signal, timeout, cancel, or the daemon refused the run
deniedYesThe API could not deliver the command to the daemon

Valid transitions

FromTo
pendingrunning, denied, killed
runningexited, killed

Terminal states are final.


CLI equivalent

bash
1# On the remote machine: opt in to command execution2belt remote --exec34# From any authenticated client: run a command and stream output5belt remote exec remote_abc123 -- ls -la6belt remote exec remote_abc123 -- bash -c "echo hi && uname -a"

belt remote exec dispatches via POST /remotes/{id}/execs, polls GET /execs/{id}/output with after_seq, and exits with the remote command's exit code.

Flags: --cwd, --timeout (seconds), --pty. The command is destructive. belt prompts for confirmation unless --yes is set.


Remotes API: register hosts, exec_enabled, WebSocket protocol

REST overview: authentication, cursor pagination, response format

we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.