> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pre.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Run browser tasks

> Submit a task array and receive JSON, an async run ID, or a live SSE stream.

Always pass a `tasks` array, including for a single task. Each request creates one run, called a batch in response types. [Authentication](/api-reference/authentication) uses `Authorization: Bearer $PREDEV_API_KEY` or `x-api-key`.

## Task controls

Every task needs a full HTTP(S) `url` and either a nonblank `instruction` or a non-empty `output` JSON Schema object. String-valued `input` is optional and does not replace instructions. Choose `mode: "extract"` for schema-oriented reads or `mode: "agent"` for goal-driven navigation; `auto` lets the service choose.

`maxSteps` and `maxDurationSeconds` set per-task budgets. For compatibility with MCP, use `1`–`50` steps and `5`–`600` seconds. REST also accepts the older `maxIterations` and `timeoutMs` names; those take precedence if both forms are sent. Do not send both forms in new code. Defaults vary with the task and execution path, so set an explicit budget when your workflow depends on one.

```json theme={null}
{
  "tasks": [{
    "url": "https://example.com",
    "instruction": "Extract the main page heading.",
    "output": {
      "type": "object",
      "properties": { "heading": { "type": "string" } },
      "required": ["heading"]
    },
    "mode": "extract",
    "maxSteps": 10,
    "maxDurationSeconds": 120
  }],
  "concurrency": 5,
  "async": true
}
```

When `output` is omitted, schema inference may be attempted. Supply your own schema for a predictable contract; a successful task does not always have `data`.

## Input validation

The service validates the entire batch before charging credits, creating a run, or queueing browser work. Malformed URLs, missing instructions without an output schema, and domains with no DNS address return an actionable error with a `code`, a zero-based `taskIndex`, and a `field` when applicable.

DNS verification has a five-second request budget. Temporary DNS failures return `503` with `URL_CHECK_UNAVAILABLE`; retry the submission later. No tasks are started when verification fails. This check verifies the hostname, not page availability: authenticated pages and bot-protected sites remain eligible for browser execution.

The dashboard applies the same task and URL format checks before enabling Run. CSV instructions are checked after row-variable interpolation. Output-schema-only extraction remains supported through the API and MCP.

## Synchronous

With neither `async` nor `stream` enabled, the connection waits for a `BatchResult`. Use this for short tasks. The [quickstart](/browser-agents/quickstart) contains complete curl and SDK examples.

## Async

With `async: true`, HTTP `200` returns an initial result such as:

```json theme={null}
{
  "id": "507f1f77bcf86cd799439011",
  "total": 1,
  "completed": 0,
  "results": [],
  "totalCreditsUsed": 0,
  "status": "processing"
}
```

Save **`id`**, then [poll the run](/browser-agents/api/task-status) or [attach an SSE stream](/browser-agents/api/stream-task). `totalCreditsUsed: 0` on this initial response does not mean no credit floor was charged at submission.

## Streaming

With `stream: true`, the response is `text/event-stream`. If both `stream` and `async` are true, **streaming takes precedence**; the server does not reject that combination. Send only your intended mode for clarity.

```bash theme={null}
curl --fail-with-body -N https://api.pre.dev/browser-agent \
  -H "Authorization: Bearer $PREDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tasks": [{"url":"https://example.com","instruction":"Read the main heading."}],
    "stream": true
  }'
```

| SSE event     | `data` payload                                     |
| ------------- | -------------------------------------------------- |
| `task_event`  | `{ taskIndex, type, timestamp, iteration?, data }` |
| `task_result` | `{ taskIndex, ...taskResult }`                     |
| `done`        | Full `BatchResult`                                 |
| `error`       | `{ error, code?, actionUrl?, taskIndex?, field? }` |

Lines beginning with `:` are keepalive comments. The task index is zero-based. Individual task `done` events inside `task_event` do not finish the batch; wait for the outer SSE `done` event and inspect all task statuses.

A submission stream does not provide the initial `snapshot` event or reliably expose a run ID before completion. Use async submission followed by an [existing-run stream](/browser-agents/api/stream-task) when you need a saved ID for recovery. Disconnecting does not cancel the work.

## Billing and limits

* The default request ceiling is **1,000 tasks**. Your account's in-flight cap can be much smaller and counts every submitted task, including queued work.
* `concurrency` defaults to **5** and is clamped to **1–20**. It controls parallelism within the run; it does not let you exceed your account limit.
* Submission checks the credit floor of **0.1 credits per task**. Successful tasks settle at at least that floor, with usage increasing for more complex work. Failed tasks settle at zero and their prepaid floor is refunded.
* Browser billing uses **\$0.10 per credit**. Treat the returned `creditsUsed` and `totalCreditsUsed` as the recorded task charges, not a forecast or a reserved amount.
* Free accounts have a limited browser trial budget in addition to the account credit balance. An exhausted trial returns `SUBSCRIPTION_REQUIRED`.

Use [queue status](/browser-agents/api/queue-status) to size batches and [errors](/api-reference/errors) to handle `QUEUE_FULL`, `RATE_LIMITED`, and billing responses. Capacity snapshots are advisory; another submission can consume capacity before yours arrives.

## Idempotency

Send an `Idempotency-Key` header, or `idempotencyKey` in the JSON body, to recover an existing run from the last **24 hours**. The header takes precedence. Use a unique key per logical submission and keep the payload stable across retries.

A matching existing run returns HTTP `200` as **JSON**, including when `stream: true` was requested. Check the response content type. The current SDK methods and MCP tool do not expose this option; use direct REST when needed. See [retry semantics](/api-reference/errors#retry-submissions).

## Response schemas

The generated schema below describes the run and task fields. [Get run status](/browser-agents/api/task-status) explains pending entries, task outcomes, retry counts, and timelines. The `completed` count alone is not a reliable completion signal; use batch `status`.


## OpenAPI

````yaml api-reference/openapi.json POST /browser-agent
openapi: 3.1.0
info:
  title: pre.dev API
  description: >-
    Public REST API for software specifications, browser automation, proposal
    assessment, and credit balance. Base URL: https://api.pre.dev. MCP is
    documented separately at https://docs.pre.dev/mcp/tools.
  version: 1.1.0
  contact:
    name: pre.dev Support
    url: https://pre.dev
    email: support@pre.dev
  license:
    name: Proprietary
    url: https://pre.dev/terms
servers:
  - url: https://api.pre.dev
    description: Production API Server
security:
  - apiKeyAuth: []
  - xApiKey: []
tags:
  - name: Specifications
  - name: Browser Agents
  - name: Proposals
  - name: Account
paths:
  /browser-agent:
    post:
      tags:
        - Browser Agents
      summary: Run browser tasks
      description: >-
        Default: synchronous JSON. async=true returns an ID. stream=true takes
        precedence and returns SSE task_event, task_result, done (full result),
        or error. A matching retry key returns JSON even when stream=true. A
        disconnected client does not cancel execution.
      operationId: runTask
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
          description: >-
            Optional user-scoped 24-hour retry lookup. Reuse only for the same
            logical submission; concurrent first requests can still duplicate
            work.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchRequest'
            example:
              tasks:
                - url: https://example.com
                  instruction: Extract the main page heading.
                  output:
                    type: object
                    properties:
                      heading:
                        type: string
                    required:
                      - heading
                  mode: extract
                  maxSteps: 10
                  maxDurationSeconds: 60
              async: true
      responses:
        '200':
          description: >-
            Batch result, asynchronous ID, or SSE stream. Inspect Content-Type
            before parsing. A done batch can contain failed tasks; inspect each
            task status.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResult'
              examples:
                submitted:
                  summary: Async submission
                  value:
                    id: 507f1f77bcf86cd799439011
                    total: 1
                    completed: 0
                    results: []
                    totalCreditsUsed: 0
                    status: processing
                completed:
                  summary: Completed run (illustrative)
                  value:
                    id: 507f1f77bcf86cd799439011
                    total: 1
                    completed: 1
                    results:
                      - url: https://example.com
                        status: SUCCESS
                        data:
                          heading: Example Domain
                        creditsUsed: 0.1
                    totalCreditsUsed: 0.1
                    status: completed
            text/event-stream:
              schema:
                type: string
              example: >+
                event: task_event

                data:
                {"taskIndex":0,"type":"navigation","timestamp":1788739200000,"data":{"url":"https://example.com"}}


                event: task_result

                data: {"taskIndex":0,"status":"SUCCESS","data":{"title":"Example
                Domain"},"creditsUsed":0.1}


                event: done

                data:
                {"id":"64b7f3e1c2a9d5e6f8a01234","status":"completed","total":1,"completed":1,"results":[{"status":"SUCCESS","data":{"title":"Example
                Domain"},"creditsUsed":0.1}],"totalCreditsUsed":0.1}

        '400':
          description: >-
            Invalid task input, malformed or unresolvable URL, missing
            instructions/output schema, or oversized batch. No work is started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing, invalid, or ineligible authentication.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Insufficient balance or a billing gate.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate or inflight limit reached.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Request failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            Streaming capacity unavailable, or temporary DNS verification
            failure (URL_CHECK_UNAVAILABLE). No tasks start when input
            verification fails.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-codeSamples:
        - lang: cURL
          source: |-
            curl --fail-with-body https://api.pre.dev/browser-agent \
              -H "Authorization: Bearer $PREDEV_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
              "tasks": [
                {
                  "url": "https://example.com",
                  "instruction": "Extract the main page heading.",
                  "output": {
                    "type": "object",
                    "properties": {
                      "heading": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "heading"
                    ]
                  },
                  "mode": "extract",
                  "maxSteps": 10,
                  "maxDurationSeconds": 60
                }
              ],
              "async": true
            }'
components:
  schemas:
    BatchRequest:
      type: object
      required:
        - tasks
      properties:
        tasks:
          type: array
          items:
            $ref: '#/components/schemas/Task'
          minItems: 1
          description: >-
            One or more tasks. Default server limit is 1,000, configurable by
            deployment; BATCH_TOO_LARGE reports the active limit.
        concurrency:
          type: integer
          description: >-
            Requested parallelism; defaults to 5 and is clamped to 1–20. Account
            and service capacity may reduce effective parallelism.
          minimum: 1
          maximum: 20
          default: 5
        async:
          type: boolean
          default: false
          description: Return the batch ID immediately, then poll or attach to its stream.
        stream:
          type: boolean
          default: false
          description: Return SSE; takes precedence over async.
        idempotencyKey:
          type: string
          description: >-
            Optional retry lookup key. Idempotency-Key header takes precedence.
            User-scoped lookup lasts 24 hours; concurrent first requests are not
            atomically deduplicated.
    BatchResult:
      type: object
      required:
        - id
        - status
        - results
      properties:
        id:
          type: string
          description: 24-character record ID.
          pattern: ^[a-fA-F0-9]{24}$
        name:
          anyOf:
            - type: string
            - type: 'null'
        taskNames:
          type: array
          items:
            type: string
        total:
          type: integer
        completed:
          type: integer
          description: >-
            Counts result slots, including pending/running placeholders or
            nulls. Do not use this as the completion signal.
        results:
          type: array
          items:
            anyOf:
              - $ref: '#/components/schemas/TaskResult'
              - type: 'null'
          description: >-
            Ordered by task index. Slots can be null or partial until a result
            arrives.
        totalCreditsUsed:
          type: number
        status:
          type: string
          enum:
            - processing
            - completed
            - failed
        createdAt:
          type: string
          format: date-time
        completedAt:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
        liveEvents:
          type: array
          items:
            type: array
            items:
              $ref: '#/components/schemas/RunnerEvent'
          description: >-
            Per-task events when includeEvents=true and live events are
            available.
        error:
          anyOf:
            - type: string
            - type: 'null'
      additionalProperties: true
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        message:
          type: string
          description: Optional detail; not returned by every endpoint.
        code:
          type: string
          description: Machine-readable code when available.
        actionUrl:
          type: string
          format: uri
        requiresSubscription:
          type: boolean
        trialsUsed:
          type: integer
        maxTrials:
          type: integer
      additionalProperties: true
    Task:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          description: >-
            Full starting HTTP(S) URL. Domains must resolve to at least one IPv4
            or IPv6 address.
          format: uri
        instruction:
          type: string
          description: Goal and constraints for the task.
        input:
          type: object
          properties: {}
          additionalProperties:
            type: string
          description: Named string inputs available to the runner.
        output:
          type: object
          properties: {}
          additionalProperties: true
          description: >-
            JSON Schema for extracted data. If omitted, the runner may infer a
            schema.
          minProperties: 1
        successCondition:
          type: string
          description: Natural-language completion check.
        mode:
          type: string
          description: >-
            auto chooses extraction when an output schema is provided; agent
            handles interaction.
          enum:
            - auto
            - extract
            - agent
          default: auto
        maxSteps:
          type: integer
          description: >-
            Planning iteration budget. MCP accepts 1–50; use this range across
            clients. REST forwards the value without equivalent range
            validation.
          minimum: 1
          maximum: 50
        maxDurationSeconds:
          type: integer
          description: >-
            Wall-clock budget in seconds. MCP accepts 5–600; use this range
            across clients. Defaults vary by execution path.
          minimum: 5
          maximum: 600
        maxIterations:
          type: integer
          description: >-
            Legacy alias of maxSteps. If both are supplied, maxIterations takes
            precedence.
          deprecated: true
        timeoutMs:
          type: integer
          description: >-
            Legacy millisecond budget. If both are supplied, timeoutMs takes
            precedence over maxDurationSeconds.
          deprecated: true
      description: >-
        A full HTTP(S) URL and either nonblank instructions or a non-empty
        output schema are required. The entire batch is validated before billing
        or queueing.
      anyOf:
        - required:
            - instruction
          properties:
            instruction:
              type: string
              pattern: \S
        - required:
            - output
    TaskResult:
      type: object
      properties:
        url:
          type: string
        name:
          type: string
        instruction:
          type: string
        input:
          type: object
          properties: {}
          additionalProperties: true
        output:
          type: object
          properties: {}
          additionalProperties: true
        status:
          type: string
          description: >-
            PENDING and RUNNING are status placeholders; all other listed values
            are terminal task outcomes.
          enum:
            - PENDING
            - RUNNING
            - SUCCESS
            - ERROR
            - TIMEOUT
            - BLOCKED
            - CAPTCHA_FAILED
            - LOOP
            - NO_TARGET
        data:
          description: >-
            Extracted result; shape follows the requested or inferred schema.
            May be null or omitted.
        creditsUsed:
          type: number
          description: >-
            Settled task charge: SUCCESS has a 0.1-credit floor; non-SUCCESS
            tasks have zero charge. Submission may reserve credits before
            settlement.
        durationMs:
          type: integer
          description: Wall-clock task duration in milliseconds.
        error:
          anyOf:
            - type: string
            - type: 'null'
        attempts:
          type: integer
        queuePosition:
          anyOf:
            - type: integer
              description: Queue estimate; 0 when running.
            - type: 'null'
        events:
          type: array
          items:
            $ref: '#/components/schemas/RunnerEvent'
          description: Available timeline when includeEvents=true.
      additionalProperties: true
    RunnerEvent:
      type: object
      required:
        - type
        - timestamp
      properties:
        type:
          type: string
          description: >-
            Extensible event type, for example navigation, screenshot, plan,
            action, validation, waiting, done, or error.
        timestamp:
          type: number
          description: Unix timestamp in milliseconds.
        iteration:
          type: integer
        data:
          description: >-
            Event-specific payload. Screenshot data is not guaranteed to be a
            URL.
      additionalProperties: true
  securitySchemes:
    apiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: Use a pre.dev API key from https://pre.dev/projects/key.
    xApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: 'Alternative to Authorization: Bearer.'

````