POST /api/v1/browsing/async
Creates a browsing task and returns task_id immediately.
Request body (JSON):
| Field | Type | Required | Description |
|---|---|---|---|
task | string | One of task / script | Natural-language instruction |
script | string | One of task / script | Custom Python snippet — granted per API key after a manager approves the request. See Custom Scripts |
filter.country_iso | string | No | Route to nodes in a country (e.g. DE, US) |
filter.node_uid | string | No | Route to one specific node by UID. Mutually exclusive with filter.country_iso — sending both returns 400 |
session_key | string | No | Group tasks into a shared session (max 128 chars) |
timeout_sec | uint32 | No | How long to wait, in seconds (max 3 hours = 10800). Omitted: 10 minutes |
fanout | uint32 | No | Nodes to race (1–10, default 1) |
ttl_days | uint32 | No | How many days the task’s request and result are kept (1–30). Omitted: 7. See Retention |
screenshots.mode | string | If screenshots set | final_only, every_step, or on_navigation |
screenshots.full_page | bool | No | Full-page capture (default true) |
emulate_human | bool | No | Move the pointer along a path and type character by character instead of dispatching input instantly. Adds roughly a quarter to the task’s latency; off by default |
country_iso_exclude | string[] | No | Exclude countries; RU is added by default |
uv_args | string | No | Extra Python packages for custom scripts (max 1024 chars) |
template | string | No | How the task drives the browser. Omit for the default. See Templates |
Unknown JSON fields are rejected (400).
Retention
A task’s request (the task text or script) and its result (payload) are
kept for ttl_days after the task is created — 7 days unless you say otherwise, 30 at
most — and then deleted. Collect the result within that window; it is not recoverable
afterwards.
The task itself is not deleted: status keeps answering with the status, timings and
traffic figures, and once the result is gone it says so with "payload_expired": true
instead of a payload. The day the result goes away is in payload_expires_on.
Templates
template picks how the task drives the browser. Omit it for the default. An unknown
value is rejected with 400.
| Value | Use |
|---|---|
browsing_script_template | Default |
browsing_script_stealth_template | Sites that fingerprint the browser |
browsing_script_mobile_template | Drive the page as a mobile browser |
Response (200):
{ "task_id": "web:550e8400-e29b-41d4-a716-446655440000" }curl -sS -X POST "https://llm.dat.ai/api/v1/browsing/async" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"task": "Open https://example.com and summarize the page",
"filter": { "country_iso": "DE" },
"screenshots": { "mode": "final_only", "full_page": true },
"fanout": 1,
"timeout_sec": 600
}'POST /api/v1/browsing/sync
Same request body as async. Blocks until the task completes or times out — 10 minutes
unless timeout_sec says otherwise.
Response (200):
{
"task_id": "web:...",
"success": true,
"payload": { "...": "..." },
"execution_time_ms": 12345,
"traffic_in": 184320,
"traffic_out": 4096,
"traffic_total": 188416
}On failure, success is false and error contains a message. Timeout returns 504 with "Task timeout".
Traffic fields:
| Field | Meaning |
|---|---|
traffic_in | Bytes the task downloaded, in bytes |
traffic_out | Bytes the task uploaded, in bytes |
traffic_total | traffic_in + traffic_out — the figure your usage is measured against |
Traffic is reported only for a task that finished and produced a result. The three fields are omitted when the run failed or the traffic could not be measured.
GET /api/v1/browsing/status
Poll task status and result.
Query: task_id (required)
curl -sS "https://llm.dat.ai/api/v1/browsing/status?task_id=web:YOUR_TASK_ID" \
-H "Authorization: Bearer YOUR_API_KEY"Response (200):
{
"task_id": "web:...",
"status": "completed",
"created_at": "2026-01-13T12:34:56Z",
"assigned_at": "2026-01-13T12:34:57Z",
"started_at": "2026-01-13T12:35:00Z",
"completed_at": "2026-01-13T12:35:42Z",
"payload_expires_on": "2026-01-20",
"success": true,
"payload": { "...": "..." },
"execution_time_ms": 42000,
"traffic_in": 184320,
"traffic_out": 4096,
"traffic_total": 188416
}status | Meaning |
|---|---|
queued | Waiting for a node |
assigned | Node selected |
running | Executing |
completed | Finished (includes success, payload, optional error) |
failed | Failed |
cancelled | Cancelled |
success, payload, and error are included only when status is completed.
payload_expires_on is the day after which the result is deleted (see
Retention). Past that day the response carries "payload_expired": true
and no payload; everything else stays.
GET /api/v1/browsing/screenshots/task_id/filename
Download a screenshot captured during a browsing task.
curl -sS "https://llm.dat.ai/api/v1/browsing/screenshots/web%3AYOUR_TASK_ID/step-001.png" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o screenshot.pngtask_idandfilenamemust be URL-encoded in the path- Returns the image file on success (200)
- 403 if the task belongs to another account
- 404 if the task or screenshot does not exist
Screenshots are only available when screenshots was set in the create request. Files are kept for up to 5 days, then deleted automatically.
Errors
All browsing endpoints return { "error": "..." }.
| Status | Cause |
|---|---|
| 400 | Invalid JSON, unknown field, neither task nor script, missing task_id, unknown template, both country_iso and node_uid |
| 401 | Missing or invalid API key |
| 402 | No active subscription, or insufficient balance |
| 403 | Task belongs to another account, or script / uv_args not enabled for this API key |
| 404 | Task or screenshot not found |
| 405 | Wrong HTTP method for the endpoint |
| 504 | sync waited past the timeout — the task itself keeps running, poll status |