Create a task
Needs the plan's agentRuns. The plan limits tasks (Free 1) and schedules switched on (Free 0, Hobby 5, Startup 50, Scale no limit): 402 plan_limit beyond. A secret variable has no default (its value is never stored), and a task with one cannot have a schedule. 60 changes per minute per project.
POST
/v1/tasksRequest
| Method and path | POST/v1/tasks |
|---|---|
| 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. |
| Safe retries | Send an Idempotency-Key header to retry without creating anything twice. See Idempotency keys. |
| Rate limit | Yes. See Rate limits for the numbers and headers. |
Headers
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
Idempotency-Key | string | – | – | Makes a retry safe: the same key and body within 24 hours returns the first response (with Idempotent-Replayed: true) instead of creating something twice. 1 to 255 printable ASCII characters without spaces, e.g. a UUID. Keys belong to the project (a new API key is replayed only to its caller). At most 300 new keys per minute per project (429). 1 to 255 characters. |
Body
JSON with content-type: application/json. Required.
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
namerequired | string | – | – | 1 to 100 characters. |
instructionrequired | string | – | – | What the agent does, with %name% where a variable goes. Up to 20000 characters. |
variables | object[] | – | – | Up to 50 items. |
variables[].namerequired | string | – | – | Up to 64 characters. Pattern: ^[A-Za-z_][A-Za-z0-9_]*$. |
variables[].secret | boolean | false | – | The agent types it without seeing it (%name%). Its value is never stored: no default, it comes with every run, and the task cannot have a schedule. |
variables[].default | string | null | – | – | Non-secret variables only. Up to 8000 characters. |
variables[].description | string | null | – | – | Up to 500 characters. |
variables[].origins | string[] | null | – | – | Secret variables only (as agent variables' origins). 1 to 20 items. |
variables[].shell | boolean | false | – | Secret variables only: bash commands may use it. |
credentials | string[] | – | – | Credentials (by name) each run gets as placeholders, exactly like credentials on POST /v1/agent/runs: each must exist with scope "agent" or "all" (404 credential_not_found, 400 credential_not_for_ai), may not share a variable's name, and needs allowWithExtensions with extensions. Scheduled tasks may use them. Checked again at every run: a credential deleted since fails the run (credential_not_found). Uses are audited with usedBy task_run. Up to 50 items. |
output | object | – | – | Structured output: a JSON Schema (at most 32 KB, 2,000 parts, 32 levels; local $ref only) the answer must match. The model gets a finish tool taking it; an answer that does not match gets one repair try, then the run fails with errorCode output_invalid. Enforced: type, enum, const, properties, required, additionalProperties, items, prefixItems, min/maxItems, uniqueItems, min/maxLength, minimum, maximum, exclusiveMinimum/Maximum, multipleOf, min/maxProperties, allOf, anyOf, oneOf, not, $ref. Given to the model only: pattern, patternProperties, format. |
session | object | – | – | The settings of each run's own session (a SessionSpec, so a task can be shell only: {browser: false, shell: true}). env is stored sealed and read back as names only. A custom proxy's password is never returned. |
session.browser | boolean | object | – | – | true or omitted: a browser with the defaults; false: none; an object: a browser with these settings. |
session.browser.mode | string | standard | standard, realistic | realistic puts the clock and language on the proxy's country. It never changes what the browser reports about itself. |
session.browser.locale | string | – | – | BCP 47, e.g. de-DE. Wins over the mode. |
session.browser.timezone | string | – | – | IANA, e.g. Europe/Berlin. Wins over the mode. |
session.shell | boolean | false | – | A bash shell with Python, Node, ffmpeg and sudo, sharing /workspace. |
session.timeout | integer | 300 | – | Seconds, up to the plan's maxTimeoutSeconds (402 plan_limit). At least 60. |
session.idleTimeout | integer | null | – | – | Opt-in (default off): the session stops (stopReason idle) after this many seconds without activity: 30 to its timeout. Activity: CDP commands through the gateway, live-view input, terminal keys, exec, files calls, actions and steps, scripts, agent steps and messages; an agent run working in the session (or one that can still be resumed) counts the whole time. Checked every few seconds. null switches it off (PATCH). At least 30. |
session.keepAlive | boolean | false | – | Keep a browser-only session after its last client disconnects. |
session.viewport | object | – | – | |
session.viewport.widthrequired | integer | – | – | From 200 to 3840. |
session.viewport.heightrequired | integer | – | – | From 200 to 2160. |
session.userMetadata | object | – | – | |
session.profile | object | – | – | |
session.profile.idrequired | string | – | – | |
session.profile.persist | boolean | false | – | Save the browser's logins back into the profile at the end. |
session.recordSession | boolean | true | – | |
session.setup | string[] | – | – | Shell commands run in order when the session starts, and again after a resume (needs shell). Up to 20 items. |
session.proxy | boolean | null | object | object[] | – | – | true = a residential US proxy; an object = one proxy; a list = rules by site (at most 10); null or false = none. |
session.proxy.typerequired | string | – | residential, datacenter, custom | |
session.proxy.country | string | – | – | Two-letter country code (residential and datacenter). |
session.proxy.state | string | – | – | Residential, US states, e.g. us_california (implies US). |
session.proxy.city | string | – | – | Residential, e.g. los_angeles (needs country). |
session.proxy.ip | string | – | sticky, rotating | Default sticky for sessions and crawls, rotating for fetch, screenshot, pdf and extract. |
session.proxy.scope | string | browser | browser, all | all also routes the session's shell. |
session.proxy.server | string | – | – | custom: your proxy, http://host:port or https://host:port, on a public address. |
session.proxy.username | string | – | – | |
session.proxy.password | string | – | – | Stored encrypted; never returned. |
session.proxy[].domainPattern | string | – | – | Up to 256 characters. |
session.captcha | string | – | ask, ignore, solve | What happens when a CAPTCHA waits for a person. ask (default): agent runs and steps pause and hand over. ignore: they carry on. solve (opt-in, paid plans): the platform tries to solve it first. |
session.blockAds | boolean | false | – | Refuse requests to ad and tracker sites inside the machine (its local proxy), with or without a session proxy. Blocked requests are counted in blockedRequests and reported in lifecycle events. |
session.cookieBanners | string | reject | reject, off | reject: answer consent banners of the common platforms with "Reject all" or "Necessary only" (never accept), else hide them, in every tab and frame. Each answer is a lifecycle event. |
session.extensions | string[] | – | – | Uploaded extensions (POST /v1/extensions) to load into the browser; needs the plan feature extensions. Up to 10 items. |
session.env | object | – | – | Variables for the session's shell (needs shell): new terminals, exec, scripts and setup commands get them, and they are set again on every new machine (resume, recovery). Names like the shell's ([A-Za-z_][A-Za-z0-9_]*, not PATH, HOME or BOXLINE_*), 64 KB together. Kept sealed; the session shows the names only. |
session.credentials | string[] | – | – | Credentials exported into the shell, one variable per field: a secret as $NAME, a password as $NAME_USERNAME and $NAME_PASSWORD (and boxline-otp NAME prints its 2FA code). Needs shell; the credential needs scope "shell" or "all", or shell true (else 400 credential_not_for_shell). Kept in the machine's memory only (never a file in /workspace), set again on every new machine, and hidden in exec, script and terminal output. Up to 50 items. |
allowWithExtensions | boolean | false | – | Needed for a task with secret variables or credentials and a session with extensions (400 variables_with_extensions otherwise). |
model | object | – | – | |
model.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.model | string | – | – | |
maxSteps | integer | null | 30 | – | null: no step limit for its runs. From 1 to 1000. |
maxCostUsd | number | null | – | – | Each run's money budget (as maxCostUsd on agent runs); default none. From 0.01 to 100. |
notifyOnFailure | string | null | – | email, null | Stored only; emails are not sent yet. |
schedule | object | – | – | |
schedule.cron | string | – | – | Five fields (minute hour day-of-month month day-of-week), names JAN–DEC and SUN–SAT, or @hourly, @daily, @weekly, @monthly, @yearly. At most every 5 minutes. |
schedule.timezone | string | UTC | – | An IANA time zone; the cron is read on its clock. |
schedule.variables | object | – | – | Values for non-secret variables. |
schedule.enabled | boolean | true | – |
curl -X POST "https://api.boxline.dev/v1/tasks" \ -H "x-api-key: $BOXLINE_API_KEY" \ -H "content-type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "name": "Books by category", "instruction": "Open https://books.toscrape.com, open the category %category% and list the books on its first page with their prices", "variables": [{"name": "category", "default": "Travel"}], "output": { "type": "object", "properties": { "books": { "type": "array", "items": { "type": "object", "properties": {"title": {"type": "string"}, "price": {"type": "number"}}, "required": ["title", "price"] } } }, "required": ["books"] }, "schedule": {"cron": "0 9 * * MON-FRI", "timezone": "Europe/London"} }'import { Boxline } from "@boxline/sdk";const bx = new Boxline(); // reads BOXLINE_API_KEY and BOXLINE_API_URLconst task = await bx.tasks.create({ name: "Books by category", instruction: "Open https://books.toscrape.com, open the category %category% and list the books on its first page with their prices", variables: [{ name: "category", default: "Travel" }], output: { type: "object", properties: { books: { type: "array", items: { type: "object", properties: { title: { type: "string" }, price: { type: "number" } }, required: ["title", "price"], }, }, }, required: ["books"], }, schedule: { cron: "0 9 * * MON-FRI", timezone: "Europe/London" },});console.log(task.id, task.schedule?.nextRunAt);from boxline import Boxlinebx = Boxline() # reads BOXLINE_API_KEY and BOXLINE_API_URLtask = bx.tasks.create("Books by category", "Open https://books.toscrape.com, open the category %category% and list the books on its first page with their prices", variables=[{"name": "category", "default": "Travel"}], output={ "type": "object", "properties": { "books": { "type": "array", "items": { "type": "object", "properties": {"title": {"type": "string"}, "price": {"type": "number"}}, "required": ["title", "price"], }, }, }, "required": ["books"], }, schedule={"cron": "0 9 * * MON-FRI", "timezone": "Europe/London"},)print(task["id"], (task["schedule"] or {}).get("nextRunAt"))Responses
201 Created
The task.
Headers
RateLimit-Limit: Requests allowed in the current window of this route's limit. (Rate limits)RateLimit-Remaining: Requests left in the current window. (Rate limits)RateLimit-Reset: Seconds until the window starts again. (Rate limits)Idempotent-Replayed:truewhen this is the kept response of an earlier request with the same Idempotency-Key. (Idempotency keys)
Fields
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
id | string | – | – | |
name | string | – | – | |
instruction | string | – | – | |
variables | object[] | – | – | |
variables[].name | string | – | – | Up to 64 characters. Pattern: ^[A-Za-z_][A-Za-z0-9_]*$. |
variables[].secret | boolean | false | – | The agent types it without seeing it (%name%). Its value is never stored: no default, it comes with every run, and the task cannot have a schedule. |
variables[].default | string | null | – | – | Non-secret variables only. Up to 8000 characters. |
variables[].description | string | null | – | – | Up to 500 characters. |
variables[].origins | string[] | null | – | – | Secret variables only (as agent variables' origins). 1 to 20 items. |
variables[].shell | boolean | false | – | Secret variables only: bash commands may use it. |
credentials | string[] | – | – | Names of the credentials its runs get (never values). |
output | object | null | – | – | |
session | object | null | – | – | The settings of each run's own session (env as a list of names; the proxy without its password). |
session.browser | boolean | object | – | – | true or omitted: a browser with the defaults; false: none; an object: a browser with these settings. |
session.browser.mode | string | standard | standard, realistic | realistic puts the clock and language on the proxy's country. It never changes what the browser reports about itself. |
session.browser.locale | string | – | – | BCP 47, e.g. de-DE. Wins over the mode. |
session.browser.timezone | string | – | – | IANA, e.g. Europe/Berlin. Wins over the mode. |
session.shell | boolean | false | – | A bash shell with Python, Node, ffmpeg and sudo, sharing /workspace. |
session.timeout | integer | 300 | – | Seconds, up to the plan's maxTimeoutSeconds (402 plan_limit). At least 60. |
session.idleTimeout | integer | null | – | – | Opt-in (default off): the session stops (stopReason idle) after this many seconds without activity: 30 to its timeout. Activity: CDP commands through the gateway, live-view input, terminal keys, exec, files calls, actions and steps, scripts, agent steps and messages; an agent run working in the session (or one that can still be resumed) counts the whole time. Checked every few seconds. null switches it off (PATCH). At least 30. |
session.keepAlive | boolean | false | – | Keep a browser-only session after its last client disconnects. |
session.viewport | object | – | – | |
session.viewport.width | integer | – | – | From 200 to 3840. |
session.viewport.height | integer | – | – | From 200 to 2160. |
session.userMetadata | object | – | – | |
session.profile | object | – | – | |
session.profile.id | string | – | – | |
session.profile.persist | boolean | false | – | Save the browser's logins back into the profile at the end. |
session.recordSession | boolean | true | – | |
session.setup | string[] | – | – | Shell commands run in order when the session starts, and again after a resume (needs shell). Up to 20 items. |
session.proxy | boolean | null | object | object[] | – | – | true = a residential US proxy; an object = one proxy; a list = rules by site (at most 10); null or false = none. |
session.proxy.type | string | – | residential, datacenter, custom | |
session.proxy.country | string | – | – | Two-letter country code (residential and datacenter). |
session.proxy.state | string | – | – | Residential, US states, e.g. us_california (implies US). |
session.proxy.city | string | – | – | Residential, e.g. los_angeles (needs country). |
session.proxy.ip | string | – | sticky, rotating | Default sticky for sessions and crawls, rotating for fetch, screenshot, pdf and extract. |
session.proxy.scope | string | browser | browser, all | all also routes the session's shell. |
session.proxy.server | string | – | – | custom: your proxy, http://host:port or https://host:port, on a public address. |
session.proxy.username | string | – | – | |
session.proxy[].domainPattern | string | – | – | Up to 256 characters. |
session.captcha | string | – | ask, ignore, solve | What happens when a CAPTCHA waits for a person. ask (default): agent runs and steps pause and hand over. ignore: they carry on. solve (opt-in, paid plans): the platform tries to solve it first. |
session.blockAds | boolean | false | – | Refuse requests to ad and tracker sites inside the machine (its local proxy), with or without a session proxy. Blocked requests are counted in blockedRequests and reported in lifecycle events. |
session.cookieBanners | string | reject | reject, off | reject: answer consent banners of the common platforms with "Reject all" or "Necessary only" (never accept), else hide them, in every tab and frame. Each answer is a lifecycle event. |
session.extensions | string[] | – | – | Uploaded extensions (POST /v1/extensions) to load into the browser; needs the plan feature extensions. Up to 10 items. |
session.env | object | – | – | Variables for the session's shell (needs shell): new terminals, exec, scripts and setup commands get them, and they are set again on every new machine (resume, recovery). Names like the shell's ([A-Za-z_][A-Za-z0-9_]*, not PATH, HOME or BOXLINE_*), 64 KB together. Kept sealed; the session shows the names only. |
session.credentials | string[] | – | – | Credentials exported into the shell, one variable per field: a secret as $NAME, a password as $NAME_USERNAME and $NAME_PASSWORD (and boxline-otp NAME prints its 2FA code). Needs shell; the credential needs scope "shell" or "all", or shell true (else 400 credential_not_for_shell). Kept in the machine's memory only (never a file in /workspace), set again on every new machine, and hidden in exec, script and terminal output. Up to 50 items. |
allowWithExtensions | boolean | – | – | |
model | object | null | – | – | |
model.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.model | string | – | – | |
maxSteps | integer | null | – | – | null: no step limit (30 when the task never set one). |
maxCostUsd | number | null | – | – | |
notifyOnFailure | string | null | – | – | |
schedule | object | null | – | – | |
schedule.cron | string | – | – | |
schedule.timezone | string | – | – | |
schedule.variables | object | – | – | |
schedule.enabled | boolean | – | – | |
schedule.nextRunAt | string | null | – | – | Null while switched off. Format: date-time. |
schedule.nextRuns | string[] | – | – | The next 3 times it fires, in UTC (the first is nextRunAt), read on the schedule's time zone and daylight-saving rules; empty while switched off. Up to 3 items. |
lastRunAt | string | null | – | – | Format: date-time. |
lastRun | object | null | – | – | |
lastRun.id | string | – | – | |
lastRun.status | string | – | queued, running, paused, completed, failed, canceled | |
lastRun.errorCode | string | null | – | – | Why it stopped (max_steps, session_timeout, …), as on its agent run; null while working or when completed. |
lastRun.createdAt | string | – | – | Format: date-time. |
lastRun.finishedAt | string | null | – | – | Format: date-time. |
createdAt | string | – | – | Format: date-time. |
updatedAt | string | – | – | Format: date-time. |
{ "id": "task_Hk2Lq8Zx0Vb5Nm1C", "name": "Work account", "instruction": "…", "variables": [ { "name": "Work account", "secret": false, "default": "…", "description": "…", "origins": [ "https://*.example.com" ], "shell": false } ], "credentials": [ "…" ], "output": { "type": "object", "properties": { "title": { "type": "string" }, "price": { "type": "number" } }, "required": [ "title", "price" ] }, "session": { "browser": { "mode": "standard", "locale": "…", "timezone": "…" }, "shell": false, "timeout": 300, "idleTimeout": 30, "keepAlive": false, "viewport": { "width": 200, "height": 200 }, "userMetadata": {}, "profile": { "id": "…", "persist": false }, "recordSession": true, "setup": [ "…" ], "proxy": { "type": "residential", "country": "US", "state": "…", "city": "…", "ip": "sticky", "scope": "browser", "server": "…", "username": "…" }, "captcha": "ask", "blockAds": false, "cookieBanners": "reject", "extensions": [ "…" ], "env": {}, "credentials": [ "…" ] }, "allowWithExtensions": false, "model": { "provider": "anthropic", "model": "claude-sonnet-5-5" }, "maxSteps": 0, "maxCostUsd": 0, "notifyOnFailure": "…", "schedule": { "cron": "…", "timezone": "…", "variables": {}, "enabled": false, "nextRunAt": "2026-09-29T10:00:00.000Z", "nextRuns": [ "2026-09-29T10:00:00.000Z" ] }, "lastRunAt": "2026-09-29T10:00:00.000Z", "lastRun": { "id": "trun_Q2x9L0aPz7NmK3Jb", "status": "queued", "errorCode": "…", "createdAt": "2026-09-29T10:00:00.000Z", "finishedAt": "2026-09-29T10:00:00.000Z" }, "createdAt": "2026-09-29T10:00:00.000Z", "updatedAt": "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 |
|---|---|---|
| 400 Bad Request | invalid_request, invalid_json, invalid_cursor, invalid_idempotency_key, invalid_extension, variables_with_extensions, terms_not_accepted, invalid_reset_token, invalid_confirmation_code, wrong_password, no_password, invalid_next, invalid_oauth_token | The request is not valid. |
| 401 Unauthorized | unauthorized | Missing or invalid API key. |
| 402 Payment Required | feature_not_in_plan, spend_limit, out_of_credit, plan_limit, spend_limit, out_of_credit, organization, project, plan, credit | The plan does not include this, a monthly allowance or spending limit is used up, the organization has no credit left, or the plan allows no more of this. spend_limit and out_of_credit carry error.details.limit: organization, project, plan or credit. |
| 404 Not Found | not_found, invite_not_found, provider_unavailable | No such thing in this project (or organization), or no such route. |
| 409 Conflict | session_not_running, shell_disabled, browser_disabled, nothing_saved, not_resumable, invalid_state, conflict, email_taken, identity_in_use, provider_already_linked, last_sign_in_method, not_impersonating, machine_too_old, too_many_credential_values, limit_reached, terms_version_mismatch, no_project, last_owner, organization_not_empty, project_has_sessions, already_member, invite_pending, idempotency_in_progress | The current state does not allow it, or a request with this Idempotency-Key is still being answered. |
| 422 Unprocessable Content | idempotency_mismatch | This Idempotency-Key was already used for a different request. |
| 429 Too Many Requests | rate_limited, concurrency_limit | Too many requests, or the organization's concurrent sessions (its plan's) or the project's concurrencyCap are in use. |
{ "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.