Legacy Browser Tasks
Use a browser task for a one-off job. Use a persistent agent for recurring responsibilities and conversational history. This legacy task surface remains documented; no retirement date is specified.
Submit a task
Set API_BASE to your deployment plus /api/v1, and use a key with agents:operate. prompt is a string, not an object. Omit wait for asynchronous submission:
TASK_JSON=$(curl --fail-with-body -X POST "$API_BASE/tasks/browser-use/" \
-H "X-Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{"prompt":"Find the title of https://example.com","requires_vision":false}')
TASK_ID=$(jq -er '.id' <<<"$TASK_JSON")
The 201 response contains the task ID and representation, including prompt, requires_vision, output_schema, status, timestamps, deprecated inactive historical credit fields, and webhook metadata. agent can be null for standalone tasks; related read-only IDs may be omitted when the relation does not exist. Store the ID before doing other work.
Member-key submissions commit the task and durable publication intent together. A broker outage can leave the accepted task pending; it still returns 201 with its ID, and existing publication recovery retries dispatch. This applies without a retry key and with extended retries/admission disabled. Acceptance does not confirm execution: cancellation, ownership/generation changes, retention and the existing four-hour task timeout can prevent it. Deploy updated web writers with matching recovery workers and Beat before relying on this behavior; no new migration or feature gate is required.
Optional creation fields include:
| Field | Use |
|---|---|
agent | UUID of an accessible browser profile; omit for a standalone task |
requires_vision | Whether the browser task should use vision |
output_schema | JSON Schema for structured output, or null |
webhook | HTTP(S) completion callback URL, or null |
secrets | Write-only domain-scoped placeholders, such as {"https://example.com":{"x_username":"value","x_password":"value"}} |
wait | Optional synchronous wait, integer 0–1,350 seconds |
credits_cost is an inactive historical response field, not a creation input. Supplying it returns a credit-retirement validation error. Historical credit reads remain until an explicit breaking-release decision; usage reporting does not enforce credit budgets.
Optional Idempotency-Key support is deployment-gated. Without a retry key, a connection failure before you receive an ID remains ambiguous: inspect recent tasks before submitting again, because an automatic POST retry can create duplicate work. Default company-license enforcement requires a licensed Organization and disallows new personal execution. Authorized historical task reads remain available under their existing ownership and scope checks. Execution policy and runtime availability also apply.
Reuse a browser profile
A browser-use agent preserves a browser profile across tasks. With an Organization member key, set AGENT_ID to an existing accessible persistent agent and retrieve its browser profile ID:
AGENT_JSON=$(curl --fail-with-body "$API_BASE/agents/$AGENT_ID/" \
-H "X-Api-Key: $API_KEY")
BROWSER_AGENT_ID=$(jq -er '.browser_use_agent_id' <<<"$AGENT_JSON")
curl --fail-with-body -X POST "$API_BASE/agents/browser-use/$BROWSER_AGENT_ID/tasks/" \
-H "X-Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{"prompt":"Find the title of https://example.com"}'
Alternatively, pass its UUID as agent on the standalone task route. Organization keys cannot create standalone browser profiles. They can submit Organization-owned standalone tasks or use a browser profile belonging to an accessible persistent agent in that Organization. Standalone profile creation with a personal Administrator key is a legacy compatibility path available only when company-license enforcement is disabled.
Read status and results
Reads require agents:read. When a browser profile belongs to a persistent agent with application requests, legacy task lists, detail, result, and update representations also require that agent's complete application history to be retained and readable by the current submission principal under current ownership. This includes derived results and errors. Otherwise the response is 403 application_request_scope_required, including global collections before counts or pagination. agents:manage and inspect=true do not grant inspection on these routes. Use application request reads for scoped history. Ordinary non-application agents and standalone tasks without application lineage retain their existing workspace access rules.
Both route families offer task detail, result, update, delete, and cancel operations:
/tasks/browser-use/{id}//agents/browser-use/{agentId}/tasks/{id}/
Append result/ to read the result:
curl --fail-with-body -H "X-Api-Key: $API_KEY" \
"$API_BASE/tasks/browser-use/$TASK_ID/result/"
Result responses use HTTP 200 regardless of whether the work is finished. Inspect status:
| Status | Result payload beyond id, agent_id, and status |
|---|---|
pending, in_progress | message: "Task is not yet completed."; no result yet |
completed | result containing the stored JSON value; it can be null, with a message when no result step exists |
failed | result: null, and error_message when available |
cancelled | No successful result is promised |
List tasks through GET /tasks/browser-use/ or the profile's /tasks/ collection. These return count, next, previous, and results; use page and page_size (default 10, maximum 100). The persistent agent's /web-tasks/ endpoint is a separate bounded collection that supports limit and status=completed.
Prefer completion callbacks, with periodic result reconciliation because callbacks are single-attempt. For polling, use a bounded loop and avoid checking more often than once every 30 seconds. This interval is client guidance, not a published rate-limit guarantee.
Update, cancel, and delete
PATCH updates only supplied writable fields. Changes to prompt, output_schema, and requires_vision require a pending task that no worker has claimed. A task with durable publication intent has a fixed browser binding: changing, attaching or detaching agent returns 400, even while pending. Cancel it and submit a new task to use another profile. Untracked legacy tasks retain pending profile edits. Both PUT and PATCH check current state when saving; a worker claim, cancellation, or completion that wins the race causes input edits to return 400. Webhook-only edits remain available on retained running or terminal tasks and preserve execution state and results. Deleted or retention-purged tasks return 404 on update. status is read-only. metadata is not a supported writable field and is ignored. Use the generated request schema instead of treating task objects as arbitrary metadata stores.
secrets follows the same pending, unclaimed restriction on both detail routes and with or without the strict contract header. Supplying a nonempty domain map replaces the entire task credential snapshot: omitted old domains and placeholder keys are removed. There is no merge. Omit secrets to preserve the current snapshot on either PUT or PATCH; send "secrets": {} to clear it. null, flat maps, non-string values and empty nested domain maps reject with 400. Creation still rejects explicit empty/null maps. Domains are normalized and must remain distinct after normalization; for example, supplying both example.com and https://example.com is ambiguous and rejects.
Secrets and any other supplied inputs save atomically. A failed validation or winning worker claim leaves the whole edit unchanged. Unavailable credential encryption returns 503 task_secrets_unavailable without applying the edit. Clearing does not require decrypting the old snapshot. It removes task injection only; source agent/global secrets, provider credentials and saved browser cookies are separate.
Creation automatically queues work, so the worker may claim before an update arrives. Supply credentials at creation when they must be available for the initial run. A successful update returns 200 with the usual task representation and an updated timestamp, without plaintext, encrypted credentials or key lists. This acknowledges stored input, not successful authentication or eventual execution. GET cannot verify a credential value. Task updates have no conditional revision or idempotency guarantee; reconcile a lost response before deciding on another write.
To stop work, send a bodyless POST to cancel/:
curl --fail-with-body -X POST -H "X-Api-Key: $API_KEY" \
"$API_BASE/tasks/browser-use/$TASK_ID/cancel/"
Successful cancellation returns 200 with status: "cancelled" and a message. A terminal task that cannot be cancelled returns 409; re-read its status. DELETE soft-deletes the record from lists and lookups and returns 204. It does not cancel running work. Cancel first if stopping execution is your intent. Deletion requires agents:manage; task creation, update, and cancellation require agents:operate.
Synchronous waits
For a short interactive task, set a positive wait value up to 1,350 seconds. The task is durably accepted before the server observes committed state; a wait never publishes another task. The 201 response can include result, error_message, or wait_error alongside the task fields. A timeout returns the observed pending or in_progress state with wait_error: "wait_timeout". An unavailable observation returns the acceptance snapshot with task_state_unavailable or task_access_unavailable, without newly read result content. A timeout or waiting error does not cancel background work: preserve the task ID and reconcile through /result/ when authorized.
Zero makes one immediate observation after acceptance. Omission is the defined asynchronous path, and keyed or admission-enforced submissions require omission. An HTTP proxy or client may time out before a positive wait completes. See Async vs sync.
Retrying asynchronous creation
When extended retries are enabled, both POST /api/v1/tasks/browser-use/ and POST /api/v1/agents/browser-use/{agentId}/tasks/ accept an optional member-key Idempotency-Key. Omit wait entirely: explicit positive, zero or null waits with a key return 400 unsupported_idempotent_wait without a task. Existing no-key waits continue to work. Keep the route, agent, prompt, schema, callback and other body fields identical to replay the original 201 task representation. Read current status/result separately. Changed input conflicts, and current referenced-agent ownership is checked on every retry. Task, receipt and durable publication intent commit together; broker failure recovery creates no second task. This does not replay unknown browser/provider effects. See retry lifetime and deployment.