Skip to main content

Base URL

https://api.pre.dev/api/v1/browser-agents
The legacy path /api/v1/browser-tasks still works as an alias — no action needed if you’re already integrated.

Authentication

All endpoints require Authorization: Bearer <PREDEV_API_KEY>. Your API key is either your SuperTokens solo userId (solo accounts) or your enterprise org API key (enterprise).

POST / — run a batch

Run one or more browser-agent tasks.

Request body

{
  tasks: Array<{
    url: string;                             // required: starting page URL
    instruction?: string;                    // natural-language goal
    input?: Record<string, string>;          // form values, credentials, queries
    output?: object;                         // JSON Schema for structured extraction
    successCondition?: string;               // optional success assertion
    timeoutMs?: number;                      // per-task max (default 240_000)
  }>;
  concurrency?: number;                      // 1-20, how many tasks run in parallel
  async?: boolean;                           // if true, returns batchId immediately
  stream?: boolean;                          // if true, SSE stream of events
  idempotencyKey?: string;                   // or via Idempotency-Key header
}
Max 1000 tasks per request. Max 5000 in-flight tasks per user.

Response (sync, async=false, default)

{
  id: string;                                // batch ObjectId
  total: number;
  completed: number;
  results: Array<{
    url: string;
    instruction?: string;
    input?: Record<string, string>;
    status: "SUCCESS" | "ERROR" | "TIMEOUT" | "BLOCKED" | "CAPTCHA_FAILED" | "LOOP" | "NO_TARGET";
    data?: unknown;                          // validated against `output` schema if set
    cost: number;                            // raw USD cost
    creditsUsed: number;                     // credits billed (1 credit = $0.10, min 0.1/task)
    durationMs: number;
    error?: string;
  }>;
  totalCost: number;
  totalCreditsUsed: number;
  status: "processing" | "completed" | "failed";
  createdAt: string;
  completedAt?: string;
}

Response (async=true)

{ id: string; status: "processing"; total: number; completed: 0; results: []; ... }
Poll GET /:id for progress.

Response (stream=true, SSE)

Returns Content-Type: text/event-stream. Frames:
event: task_event
data: { "taskIndex": 0, "type": "navigation", ... }

event: task_event
data: { "taskIndex": 0, "type": "plan", ... }

event: task_event
data: { "taskIndex": 0, "type": "screenshot", ... }

event: task_result
data: { "taskIndex": 0, "status": "SUCCESS", "data": {...} }

event: done
data: { ... full BatchResult ... }
Keepalives every 10s (:keepalive\n\n). Client disconnect stops the stream but lets the batch finish server-side.

Error codes

StatusMeaning
400Missing tasks array, too many tasks (>1000), missing url on a task
401Missing or invalid Authorization header
402Insufficient credits for the batch
429Per-user queue depth exceeded (>5000 in-flight) OR SSE pod capacity hit
500Internal error

Idempotency

Send Idempotency-Key: <your-key> header (or idempotencyKey in the body). A second POST within 24h returns the existing batch instead of creating a duplicate. Prevents double-charging on network retries.

GET /:id — fetch a batch

Get current state of a batch, including partial results for still-running tasks. Query params:
  • includeEvents=true — return the full per-task timeline (navigation, plans, screenshots, actions, validation, done)
Response same as the sync-mode POST response. Events are sanitized before return: we strip internal fields (sandbox provider names, LLM model names, token counts, sandbox IDs). The raw versions stay in our Mongo for internal debugging but never leak via the public API.

GET / — list batches

List the caller’s batches, newest first. Query params:
  • limit (1-100, default 20)
  • skip (default 0)
  • status (“processing” | “completed”)
Response:
{ batches: BatchResult[]; total: number; hasMore: boolean }

GET /_system/capacity — live capacity

Real-time snapshot of the queue + sandbox pool. Useful for dashboards.
{
  totalActive: number;
  maxSandboxes: number;       // global ceiling across all users
  perUserCap: number;         // per-user ceiling
  pending: number;
  running: number;
  claimed: number;
  failed: number;
  utilization: number;        // 0-1
  oldestQueuedAgeMs: number;
  topUsers: Array<{ userId: string; inflight: number }>;
  workers: Array<{ workerId: string; inflight: number }>;
}

Task event types (in taskEvents / SSE stream)

typeWhenKey data fields
sandboxSandbox state`status: “starting""starting_local”`
navigationPage loadedurl, title
screenshotViewport captureurl (S3), mimeType, chunkIndex, chunkCount
planLLM decided next actionsactions[], notes, done, captchaDetected
actionAction executedtype (click/fill/..), selector, success, message
waitingWaiting on somethingreason (“cloudflare”, etc.)
validationSchema check passedok
doneTask terminal statestatus, data, durationMs
errorTask erroredstatus, error, durationMs
Timestamps are Unix ms.