A valid request URL is required to generate request examples{
"run": {
"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>"
},
"leaseId": "<string>",
"manualControlUntil": "<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": "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
}
}Put a run on hold
Suspends the agent. The run moves to paused, the worker’s channels are shut until Resume (it is served no frames and its actions are refused), its deadline FREEZES, and the run’s lease slides to a fresh ten minute window so the hold has one. The worker’s steps are untouched: resuming carries on from the current screen rather than redoing what is already done.
You do not need this to act on the device. A signed-in person drives a device beside a running agent through POST /v1/devices/{deviceId}/actions without naming a lease, and the agent is informed of what you did rather than stopped. Pause is the explicit interruption you choose when you want the agent to stop while you work.
It is not a handoff. needs_user_control is the agent asking a person to do the next step on the same screen, and Resume (the console’s Done) lets it continue; this is a person suspending a run that asked for nothing, so it works from queued, running and needs_user_control alike.
Two ways the hold ends badly, and they differ. RELEASE the run’s lease while it is on hold and the run ends failed with reason lease_lost. Simply walk away, and when manualControlUntil passes the run is canceled with the explanation in detail. No new failure reason is used for either case.
Calling it again on a run already on hold is safe: nothing is re-stamped and you get the same lease and the same window back.
A valid request URL is required to generate request examples{
"run": {
"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>"
},
"leaseId": "<string>",
"manualControlUntil": "<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": "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 put on hold. A runId: an agentRunId here answers 404.
Response
The run, on hold, and the lease it acts under.
What putting a run on hold hands back: the run as it now stands, and the lease it acts under.
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.
Show child attributes
Show child attributes
The lease the run acts under, kept here for compatibility. You do not need it to act on the device: POST /v1/devices/{deviceId}/actions resolves your organisation's lease for any caller. It is still a CAPABILITY rather than a detail (release takes it), which is why GET /v1/leases never publishes it.
When the hold ends, ISO 8601. Resume the run before then to let it continue; a run nobody resumes by then is canceled. Renewing the lease extends the hold.