A valid request URL is required to generate request examples{
"runId": "<string>",
"agentRunId": "<string>",
"deviceId": "<string>",
"goal": "<string>",
"executor": "phonebase",
"state": "queued",
"stepSeq": 123,
"maxSteps": 123,
"deadlineAt": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"workerFirstContactAt": "2023-11-07T05:31:56Z",
"initiator": {
"kind": "api_key",
"viaCopilot": true,
"userId": "<string>",
"apiKeyId": "<string>",
"onBehalfOf": {
"kind": "schedule",
"scheduleId": "<string>",
"userId": "<string>",
"apiKeyId": "<string>"
}
},
"scheduleId": "<string>",
"pausedAt": "2023-11-07T05:31:56Z",
"manualControlUntil": "2023-11-07T05:31:56Z",
"lastFrame": {
"frameId": "<string>",
"viewport": {
"width": 123,
"height": 123
}
},
"recovery": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"since": "2023-11-07T05:31:56Z",
"remainingMs": 4503599627370495,
"blockedReason": null
},
"reason": "worker_reported_failure",
"detail": "<string>"
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Read a run, optionally waiting for it to move
Returns the run as it is now. With waitMs it waits for the state to leave sinceState and returns as soon as it does, or at the deadline with whatever the state is then. It never hangs: the transport is stateless and there is no push channel.
EITHER ID WORKS HERE. Send the runId POST /v1/runs returned, or the run’s agentRunId: the id every receipt the run produced carries and the one a permalink is built on. An id starting run_ is read as an agentRunId, anything else as a runId. Both answer with the same run through the same checks, waitMs included. The writes below take a runId only.
This returns the run only. Its action trail is a separate, paged resource, GET /v1/receipts?agentRunId=..., and it is not folded in here: it is a paged collection with its own cursor and its own retention.
This route applies the calling key’s device narrowing: a run on a device your key cannot address is 404, the same 404 an unknown id gets.
A valid request URL is required to generate request examples{
"runId": "<string>",
"agentRunId": "<string>",
"deviceId": "<string>",
"goal": "<string>",
"executor": "phonebase",
"state": "queued",
"stepSeq": 123,
"maxSteps": 123,
"deadlineAt": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"workerFirstContactAt": "2023-11-07T05:31:56Z",
"initiator": {
"kind": "api_key",
"viaCopilot": true,
"userId": "<string>",
"apiKeyId": "<string>",
"onBehalfOf": {
"kind": "schedule",
"scheduleId": "<string>",
"userId": "<string>",
"apiKeyId": "<string>"
}
},
"scheduleId": "<string>",
"pausedAt": "2023-11-07T05:31:56Z",
"manualControlUntil": "2023-11-07T05:31:56Z",
"lastFrame": {
"frameId": "<string>",
"viewport": {
"width": 123,
"height": 123
}
},
"recovery": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"since": "2023-11-07T05:31:56Z",
"remainingMs": 4503599627370495,
"blockedReason": null
},
"reason": "worker_reported_failure",
"detail": "<string>"
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Authorizations
The control surface credential. Send Authorization: Bearer <token>.
Two kinds of token are accepted and they are told apart by shape, not by a separate header. A token beginning pbk_ is an org scoped API key, whose public half and secret half are generated together and of which only a hash of the secret is ever stored; anything else is treated as an OAuth 2.1 access token and verified against the authorization server's keys.
Both resolve to the same context: an org, a principal and a set of scopes. Nothing downstream branches on which channel you used, with one deliberate exception, key management, which requires a signed-in person so that a key can never mint another key.
Scopes are enforced when MCP tools are REGISTERED rather than when they are called, so a tool your credential cannot use is absent from tools/list rather than refused mid gesture.
Path Parameters
The runId returned when the run was started, or the run's agentRunId (it starts run_).
Query Parameters
How long to wait for a state change, in whole milliseconds, 0 to 25000 (25 seconds). A longer wait is refused, not shortened: loop on the call instead of holding one open.
0 <= x <= 25000Return as soon as the state is no longer this one. Without it, the call returns immediately. Must be one of the run states: an unknown value is refused rather than treated as a state the run is never in. A run state.
queued, running, needs_user_control, paused, succeeded, failed, canceled Response
The run.
The public projection of a run, and who started it. The run token is deliberately absent: it is returned once, when the run is started, and never again.
What the run was asked to accomplish, in the words it was started with.
Who drives this run: phonebase (we do) or self_hosted (your worker does).
phonebase, self_hosted Where the run is now. succeeded, failed and canceled are terminal. paused means a person put the agent on hold: the worker's channels are shut until Resume. It is not needs_user_control, which can mean the agent is asking for help or an interrupted hosted run is waiting for explicit continuation. A non-null recovery distinguishes the latter.
queued, running, needs_user_control, paused, succeeded, failed, canceled Metered steps issued so far. One step is one frame served.
The run's step ceiling.
Absolute wall clock deadline, or null when the stored deadline is not a renderable instant. FROZEN while the run is paused: the time the agent spends on hold is not charged to the run, and resuming slides this forward by however long the hold lasted. It is null during recovery waiting; recovery.remainingMs reports the saved time budget.
When a self-hosted worker first reached this run, or null when none ever did. On a self_hosted run you supply the worker, and one that stays queued with null here is waiting for it. A phonebase run is driven in process and never sets this.
WHO. The same shape answers three questions: who took an action (Receipt.actor), who is holding a device (Lease.holder), and who started a run (RunView.initiator). One shape on purpose, so the three can never disagree about what a given credential is called.
Show child attributes
Show child attributes
The schedule that started this run, or null when a person or a key did. Present and null rather than absent, so you can tell those apart from an older server that does not say.
When a person put the run on hold, or null when it is not on hold. Present and null rather than absent, so a consumer can tell "not on hold" from an older server that does not report it.
When the hold ends, or null when the run is not paused. This is the clock that runs while the run is on hold, not deadlineAt. Past it, a run nobody resumed is canceled with an explanation in detail; no new failure reason is used. The name is kept from when a hold was a person's manual control window; a person needs no window to act on the device now.
The last frame this run was served, or null when it has been served none. On a finished run this is the frame the model's report was written from, because finish_run ends the turn and nothing is captured after it, so a reader can put what the model said next to the screen it read that off. viewport is the frame's own pixel geometry, which is the coordinate basis it was captured in and not necessarily the device's current size.
Show child attributes
Show child attributes
An interrupted hosted run waiting for explicit continuation, or null. Older servers may omit this field. Progress and remaining budget are preserved; no action is replayed automatically.
Show child attributes
Show child attributes
Why the run ended, when it did not simply succeed.
worker_reported_failure, budget_exhausted, deadline_exceeded, canceled_by_caller, lease_lost, interrupted_by_restart Free text about how the run ended. A worker's own report, or, when the run hit its deadline, the control plane's explanation of which kind of timeout it was.