Skip to content

API schema

Every method, event, object and error code of the Computer API, version 1

ItemValue
Schema filecomputer/schema/computer-api.v1.json, generated from computer/src/api/schema.ts
Print itopc schema, from the copy built into the CLI. opc schema <object> prints one object
field?Optional
| nullAlways present, may be null

Operations

On an HTTP route, path parameters replace sessionId, turnId, askId and subagentId. A GET takes the other fields as query parameters, other verbs as a JSON body. Unknown fields are refused with invalid_request.

MethodHTTP routeParamsResult
sessions.attachWebSocket onlysessionId, after?, tailTurns? (1 to 50), deltas?, resume?, readOnly?session, logEpoch, epochStartSeq, capabilities, earlierTurns | null, timing.serverUs
sessions.detachWebSocket onlysessionIdempty
sessions.getGET /sessions/{id}sessionId, minSeq?session
sessions.updatePATCH /sessions/{id}sessionId, idempotencyKey?, title? (1 to 200 characters), model?, effort?, speed? (fast, standard), mode?, archived?, metadata?session, seq
sessions.interruptPOST /sessions/{id}/interruptsessionId, idempotencyKey?, turnId?session, seq
sessions.compactPOST /sessions/{id}/compactsessionId, idempotencyKey?, instructions? (up to 10,000 characters)turn, delivery, duplicate, seq, timing?
sessions.suspendPOST /sessions/{id}/suspendsessionId, idempotencyKey?, ifIdle?session, seq
sessions.resumePOST /sessions/{id}/resumesessionId, idempotencyKey?session, seq
turns.sendPOST /sessions/{id}/turnssessionId, idempotencyKey?, input (1 to 100,000 characters), ifBusy? (queue, steer, interrupt)turn, delivery (started, queued, steered), duplicate, seq, timing?
turns.getGET /sessions/{id}/turns/{turnId}sessionId, turnId, waitMs? (0 to 60,000), status?, minSeq?turn
turns.cancelPOST /sessions/{id}/turns/{turnId}/cancelsessionId, turnId, idempotencyKey?turn, seq
asks.listGET /sessions/{id}/askssessionId, status?, limit? (1 to 100), cursor?asks, nextCursor | null
asks.getGET /sessions/{id}/asks/{askId}sessionId, askIdask
asks.answerPOST /sessions/{id}/asks/{askId}/answer (the body is the answer)sessionId, askId, idempotencyKey?, answerask, seq
asks.dismissPOST /sessions/{id}/asks/{askId}/dismisssessionId, askId, idempotencyKey?, message? (up to 2,000 characters)ask, seq
subagents.listGET /sessions/{id}/subagentssessionId, status? (running, all), limit? (1 to 100), cursor?subagents, nextCursor | null
subagents.getGET /sessions/{id}/subagents/{subagentId}sessionId, subagentIdsubagent
subagents.stopPOST /sessions/{id}/subagents/{subagentId}/stopsessionId, subagentId, idempotencyKey?subagent, seq
events.listGET /sessions/{id}/eventssessionId, after?, limit? (1 to 500, default 100), waitMs? (0 to 60,000), tailTurns? (1 to 50), turnId?, types?events, earlierTurns | null, lastSeq, hasMore
terminals.openWebSocket onlysessionId, cols?, rows? (1 to 1,000 each), command? (up to 10,000 characters), tty?, term? (up to 64 characters)terminal.id, terminal.channel, terminal.stderrChannel | null
terminals.resizeWebSocket onlyterminalId, cols, rowsempty
terminals.eofWebSocket onlyterminalIdempty
terminals.closeWebSocket onlyterminalIdempty
pingWebSocket onlynonetiming.serverUs

Creating a session is HTTP only: POST /sessions with CreateSessionBody: id?, input?, title? (up to 200 characters), model?, effort?, speed?, mode?, metadata?.

Routes outside the schema

The relay (computer/src/wire/) serves these. The API routes for workspace files are /sessions/{id}/workspace/files, /file and /archive; opc push and opc pull call /archive. See Files.

Relay routePurpose
GET /files/{id}/filesList a directory: path, depth (1 to 10), limit (1 to 100), cursor
GET /files/{id}/fileRead one file: path
GET /files/{id}/archiveDownload a directory or file as a tar stream: path
PUT /files/{id}/archiveUpload a tar stream as one top-level directory: path
GET /connectWebSocket upgrade
GET /healthRelay health

WebSocket notifications

Server to client:

MethodParams
readyconnectionId, server.version, server.region | null, protocol.features[], limits.maxAttached, limits.maxMessageBytes, limits.maxRequestsPerSecond, expiresAt | null, expiresInMs | null
sessions.attachedsessionId, error | null, session | null, logEpoch | null, epochStartSeq | null, capabilities | null, earlierTurns | null, timing | null (answers an attach named in the connection URL)
eventOne event
deltaOne delta
session.detachedsessionId, reason (too_far_behind, access_lost, epoch_changed, unavailable), logEpoch?, epochStartSeq?
terminal.exitedterminalId, exitCode | null, signal | null

Client to server:

MethodParams
sessions.acksessionId, seq
telemetryv (1), client.name (opc), client.version, client.os?, client.arch?, events (1 to 20)

Events

Envelope:

FieldType
idev_ and 16 characters
seqInteger from 1, increasing by one per session
createdAtTimestamp
sessionIdcs_ and 16 characters
turnIdTurn id or null
actorActor or null
typeOne of the types below
dataPer type
Typedata fields
session.createdtitle, origin, settings
session.status_changedfrom | null, to
session.updatedchanges: a map of field name to {from, to}
session.compactedbeforeTokens, afterTokens, auto
message.receivedinput, ifBusy, delivery, interruptedTurnIds[], declinedAskIds[]
turn.queuedposition, trigger, subagentId
turn.steeredmessageSeq
turn.startedmodel, effort, mode, trigger, subagentId
turn.status_changedfrom, to
turn.completedtext, durationMs, silent
turn.failederror (code, message)
turn.cancelledreason, forced, input
message.completedblockId, parentCallId, text
reasoning.completedblockId, parentCallId, text, redacted, durationMs
tool.startedsubagentId, toolName, callId, parentCallId, title, input, inputTruncated
tool.completedsubagentId, toolName, callId, parentCallId, title, output, outputTruncated, fileChanges | null (each path, status of added, modified or deleted, added, removed), durationMs
tool.failedsubagentId, toolName, callId, parentCallId, title, message, settledBy
subagent.startedsubagent
subagent.endedsubagent
ask.openedask
ask.closedask
usage.recordedmodel, inputTokens, outputTokens, reasoningTokens, cachedTokens, cacheWriteTokens, costUsd, firstTokenMs, durationMs, usedTokens, windowTokens
model.rate_limitedmodel, retryAfterMs, attempt
runtime.startingphase (computer, agent)
runtime.connectedwarm, resumed, durationMs
runtime.suspendedreason (idle, requested, lost)
files.pushedpath, files, bytes, replaced
terminal.openedterminalId, command
terminal.closedterminalId, exitCode

A client must ignore event types it does not know (Event.other: any other type, open data).

Deltas

Sent only on a WebSocket attached with deltas: true; see Events. Each has type, sessionId, turnId and data.

Typedata fields
message.deltablockId, parentCallId, text
reasoning.deltablockId, parentCallId, text
tool.preparingsubagentId, callId, toolName, path, description, lines
tool.deltacallId, text
session.compactingnone
subagent.progresssubagentId, activity, toolCalls, tokens

Objects

ObjectFields
Sessionid (cs_ and 16 characters), title, status (starting, running, waiting, idle, suspended), archived, owner (Person), origin (Origin), settings (model, effort, mode, speed), metadata, activeTurnId, queued (Turn list), asks (Ask list), subagents (Subagent list), lastTurn (TurnSummary or null), lastText, context (usedTokens, windowTokens), lastSeq, logEpoch, epochStartSeq, createdAt, lastActiveAt, syncedAt, urls.dashboard
Personid, name, email
Origintype (slack, opc, dashboard, api), client, slack (teamId, channelId, channelName, threadTs, url) or null
Actorid, name, via (slack, opc, dashboard, api), client
Turnid (tn_ and 12 characters), sessionId, status (queued, running, cancelling, completed, failed, cancelled), trigger (message, subagent), subagentId, ifBusy, input, author (Actor or null), steering (list of input, author, createdAt), createdAt, startedAt, endedAt, text, error (TurnError or null), reason (interrupted, withdrawn or null), forced, usage (Usage or null)
TurnErrorcode (model_rejected, model_unavailable, model_stream_failed, context_too_long, runtime_lost, runtime_failed, tool_failed, agent_failed), message
UsageinputTokens, outputTokens, reasoningTokens, cachedTokens, cacheWriteTokens, costUsd
Askid (ak_ and 12 characters), sessionId, turnId, kind (approval, question, secret), status (open, answered, dismissed, declined, interrupted), createdAt, closedAt, closedBy, answer, approval (toolName, callId, input, title, alwaysAllows) or null, question (questions: each id, header, text, multiSelect, options of label and description) or null, secret (name, purpose, file) or null
ApprovalAnswerdecision (allow, deny, always), message? (up to 2,000 characters), mode?
QuestionAnsweranswers: each questionId, choices[], text | null
DeclineAnswermessage, messageSeq
Subagentid (sa_ and 12 characters), sessionId, turnId, callId, name, agentType, background, status (running, completed, failed, stopped), activity, toolCalls, tokens, createdAt, endedAt, durationMs, result, resultTruncated, error (code, message) or null, stoppedBy (Actor or null)
Capabilitiesmodels (each id, name, efforts[], contextWindow, default), modes[], features (steer, compact, terminal, workspace, reasoning, subagents)
Secretname, scope (session, me, organization), sessionId, file, effective, setBy, updatedAt
Resulttype (result), subtype (success, error, cancelled, waiting), isError, sessionId, turnId, status, result, error, reason, ask, url, durationMs, usage, subagents (SubagentSummary list), turn

Result is what opc -p --output-format json prints for a turn. No operation reads or writes Secret.

Errors

An error body is code, message, and optionally status, retryable, requestId, field, reason and retryAfterMs. HTTP wraps it as {"error": {...}}; WebSocket sends it as the data of a JSON-RPC error.

JSON-RPC codeMeaning
-32700The message is not JSON
-32600Not a JSON-RPC request. Batches are not supported
-32601Unknown method
-32602Invalid params: data is code: "invalid_request", status: 400 and the field
-32000An API error: data is the error body
Groupcode values
Requestinvalid_request, unsupported_model, unsupported_effort, unsupported_mode, invalid_answer, answer_with_secret, invalid_path, invalid_archive, invalid_cursor, too_large, upgrade_required
Credential and accessunauthenticated, forbidden, admin_required, insufficient_credits
Not foundnot_found, session_not_found, turn_not_found, ask_not_found, subagent_not_found, terminal_not_found, path_not_found, secret_not_found
Conflictid_conflict, idempotency_conflict, ask_closed, session_busy, turn_not_cancellable, queue_full, cursor_ahead, path_exists, subagent_ended, too_far_behind, too_many_attached, too_many_terminals, feature_unavailable, computer_not_set_up
Retry laterrate_limited, unavailable, computer_unavailable, internal

forbidden carries a reason: missing_scope, read_only or terminal_owner_only.

Relay limits

Other limits are in Limits and defaults.

LimitValue
Sessions attached per connection20
Message size1 MiB
Requests per connection100 per second, burst 100
Connections per member50
Unsent data per connection before close 400816 MiB
Unacknowledged backlog per attached session before too_far_behind8 MiB or 10,000 events
Terminals per session8
Terminal input1 MiB per second
Terminal output frame64 KiB
Queued turns per session20
Upload or download archive1 GiB unpacked, 100,000 entries
Single file read100 MiB
Idempotency key1 to 255 characters, kept 24 hours

WebSocket close codes

CodeCause
1001Two pings missed. The relay pings every 30 seconds
1009A message over 1 MiB
1012The relay is restarting
4001The credential expired or was revoked
4008More than 16 MiB unsent
4029More than 50 connections for one member
4400The opc.v1 subprotocol was not offered
4503The relay has no signing key from the host yet. The reason is {"retryAfterMs":2000}