Get a run
Get a run.
GET
/v1/agent/runs/{id}Request
| Method and path | GET/v1/agent/runs/{id} |
|---|---|
| Base URL | https://api.boxline.dev |
| Authentication | Your API key in the x-api-key header (or Authorization: Bearer). The examples read it from BOXLINE_API_KEY. |
Path parameters
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
idrequired | string | – | – |
curl "https://api.boxline.dev/v1/agent/runs/$RUN_ID" \ -H "x-api-key: $BOXLINE_API_KEY"import { Boxline } from "@boxline/sdk";const bx = new Boxline(); // reads BOXLINE_API_KEY and BOXLINE_API_URLconst run = await bx.agent.get("RUN_ID");console.log(run.status, run.handover, run.result);from boxline import Boxlinebx = Boxline() # reads BOXLINE_API_KEY and BOXLINE_API_URLrun = bx.agent.get("RUN_ID")print(run["status"], run["handover"], run["result"])Responses
200 OK
The run with its steps.
Fields
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
id | string | – | – | |
status | string | – | running, paused, completed, failed, canceled | |
task | string | – | – | |
sessionId | string | – | – | |
provider | string | – | anthropic, openai, xai, google | Anthropic Claude, OpenAI, Grok (xAI), Google Gemini. Grok and Gemini have no computer use (mode computer is 400). |
model | string | – | – | |
keySource | string | – | project, platform | Whose key a model call uses, the project's own (project, no model charge from Boxline) or the platform's. |
mode | string | tools | tools, computer | tools: the page view and browser tools. computer: the provider's own computer-use tool on screenshots (models with supportsComputerUse; 400 otherwise, or without a browser). |
steps | object[] | – | – | |
steps[].type | string | – | text, tool, handover, resume, captcha, message, code | |
steps[].by | string | – | user, agent, captcha, auto, person | handover: who paused the run; captcha solved: who solved it (auto or person). |
steps[].from | string | – | user | message steps: who wrote it. |
steps[].id | string | – | – | message steps: the message's id (from sendAgentRunMessage). |
steps[].sentAt | string | – | – | message steps: when it was sent (at: when the model received it). Format: date-time. |
steps[].delivered | boolean | – | – | message steps: true (a message is a step once the model has it). |
steps[].at | string | – | – | Format: date-time. |
steps[].text | string | – | – | |
steps[].thought | string | – | – | tool and handover steps: the model's own words that came with the call (what it is doing and what it will do next) and, when the provider gives them in words, its reasoning (OpenAI's reasoning summaries, Claude's thinking), redacted like everything else. Also sent live as a {type:"thought", text, at} event. Up to 2000 characters. |
steps[].name | string | – | – | |
steps[].input | any | – | – | |
steps[].output | string | – | – | |
steps[].isError | boolean | – | – | |
steps[].ms | integer | – | – | |
steps[].n | integer | – | – | The step's number in the run, from 1. Steps are only added, so it never changes. A session event's data.step is this number. At least 1. |
steps[].screen | object | – | – | Browser and computer tool steps: the screen the action led to. When the model got a screenshot the frame is that exact image; otherwise the screen as the action left it. Without a recording (or while the run works with variables) only url and title. |
steps[].screen.frame | integer | – | – | The frame's number in the session's recording. |
steps[].screen.url | string | – | – | |
steps[].screen.title | string | – | – | |
steps[].screen.image | string | – | – | The frame's address (GET /v1/sessions/{id}/recording/frames/{frame}, image/jpeg; it needs the API key like the rest of the API). Format: uri. |
steps[].shell | object | – | – | bash steps. The command's output stays in output, exactly what the model got. |
steps[].shell.exitCode | integer | null | – | – | |
steps[].shell.files | object[] | – | – | Files created or changed in the workspace while the command ran (paths relative to the workspace, by path). Deleted files and changes outside the workspace are not listed. Left out by a machine from before this field. Up to 20 items. |
steps[].shell.files[].path | string | – | – | |
steps[].shell.files[].bytes | integer | – | – | |
steps[].shell.more | integer | – | – | How many more files changed beyond the 20 listed. |
steps[].usage | object | – | – | The model reply this step is the first of (the other steps of the same reply have none). The steps' tokens add up to the run's usage. |
steps[].usage.inputTokens | integer | – | – | |
steps[].usage.outputTokens | integer | – | – | |
steps[].usage.costUsd | number | null | – | – | Worked out like the run's (null for a model that is not priced). |
steps[].state | string | – | solving, waiting, solved, received, timeout | captcha steps: solving (automatic), waiting (a person's turn) or solved; code steps: waiting, received or timeout. |
steps[].kind | string | – | – | captcha steps: the CAPTCHA kind; code steps: code or link. |
steps[].credential | string | – | – | code steps: the password credential whose code or sign-in link the run waits for. |
steps[].host | string | – | – | captcha steps: the host of the page. |
steps[].reason | string | – | – | captcha waiting: why a person is asked. |
result | any | – | – | The final text; with an output schema, the JSON answer (null until it completes). |
resultText | string | null | – | – | The final text; with an output schema, a one-sentence summary of the answer. |
output | object | null | – | – | The run's output schema, or null. |
error | string | null | – | – | |
errorCode | string | null | – | – | max_steps (it used all its steps without finishing; resultText then says what is done and what is left, and resumable until when it can be resumed), max_cost (its maxCostUsd was reached; resumable, no summary), too_many_errors (maxConsecutiveErrors tool errors in a row; resumable), no_progress (the same page-reading or shell call with the same result 5 times in a row; resumable), server_restarted (the API server running it stopped while its session went on; resumable), session_timeout (its session reached its time limit while it worked), session_ended (its session ended another way; error names how), output_invalid (the answer did not match the output schema after the repair try, or the schema was too complex to check it), internal (an error on the platform's side; details only in its logs), or the code of the platform error that stopped the run (e.g. spend_limit, captcha_timeout, handover_timeout). |
resumable | object | null | – | – | Set while the run can be resumed (Resume a run): it stopped early (max_steps, max_cost, too_many_errors, no_progress, server_restarted), its session is running or stopped, until the window passes. |
resumable.until | string | – | – | Format: date-time. |
variableNames | string[] | – | – | The names of the run's own variables (never their values): resumeAgentRun needs the values again. |
maxSteps | integer | null | – | – | The run's step limit; null: none (also shown for runs from before it was kept). |
maxCostUsd | number | null | – | – | The run's money budget (USD of model cost), or null. |
maxConsecutiveErrors | integer | – | – | Tool errors in a row that stop the run. |
sessionExpiresAt | string | null | – | – | The run's session's expiresAt: when its time limit ends it. Format: date-time. |
usage | object | – | – | |
usage.inputTokens | integer | – | – | |
usage.outputTokens | integer | – | – | |
usage.costUsd | number | null | – | – | |
handover | object | null | – | – | Set while paused. |
handover.by | string | – | user, agent, captcha | |
handover.reason | string | null | – | – | |
taskId | string | null | – | – | The task that started this run. |
taskRunId | string | null | – | – | |
createdAt | string | – | – | Format: date-time. |
finishedAt | string | null | – | – | Format: date-time. |
{ "id": "…", "status": "running", "task": "Find the price of the Pro plan on example.com", "sessionId": "…", "provider": "anthropic", "model": "claude-sonnet-5-5", "keySource": "project", "mode": "tools", "steps": [ { "type": "text", "by": "user", "from": "user", "id": "…", "sentAt": "2026-09-29T10:00:00.000Z", "delivered": false, "at": "2026-09-29T10:00:00.000Z", "text": "…", "thought": "…", "name": "Work account", "input": null, "output": "…", "isError": false, "ms": 0, "n": 1, "screen": { "frame": 0, "url": "https://example.com/", "title": "Example Domain", "image": "…" }, "shell": { "exitCode": 0, "files": [ {} ], "more": 0 }, "usage": { "inputTokens": 0, "outputTokens": 0, "costUsd": 0 }, "state": "solving", "kind": "…", "credential": "…", "host": "…", "reason": "…" } ], "result": null, "resultText": "…", "output": { "type": "object", "properties": { "title": { "type": "string" }, "price": { "type": "number" } }, "required": [ "title", "price" ] }, "error": "…", "errorCode": "…", "resumable": { "until": "2026-09-29T10:00:00.000Z" }, "variableNames": [ "…" ], "maxSteps": 0, "maxCostUsd": 0, "maxConsecutiveErrors": 0, "sessionExpiresAt": "2026-09-29T10:00:00.000Z", "usage": { "inputTokens": 0, "outputTokens": 0, "costUsd": 0 }, "handover": { "by": "user", "reason": "…" }, "taskId": "…", "taskRunId": "…", "createdAt": "2026-09-29T10:00:00.000Z", "finishedAt": "2026-09-29T10:00:00.000Z"}Errors
Errors have a matching HTTP status and the same body. code is stable, so check it in your code; message is for people. See Errors and request ids.
| Status | Codes | When |
|---|---|---|
| 401 Unauthorized | unauthorized | Missing or invalid API key. |
| 404 Not Found | not_found, invite_not_found, provider_unavailable | No such thing in this project (or organization), or no such route. |
{ "error": { "code": "not_found", "message": "session not found", "requestId": "req_4fJx0aQm2Lk9Pz7N" }}Learn more
These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.