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": "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": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Cancel a run
Ends the run. An action already in flight when you cancel is refused before it reaches the device, so cancelling stops the arm rather than merely marking a record. Terminal is terminal: cancelling a finished run leaves it as it was.
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": "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": "payload_too_large",
"message": "<string>"
}
}{
"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 run to cancel. A runId: an agentRunId here answers 404.
Response
The run as it is after the call.
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.