Skip to main content
GET
/
api
/
v1
/
browser-agents
/
{id}
Get a run by id
curl --request GET \
  --url https://api.pre.dev/api/v1/browser-agents/{id} \
  --header 'Authorization: Bearer <token>'
{
  "id": "<string>",
  "total": 123,
  "completed": 123,
  "results": [
    {
      "url": "<string>",
      "instruction": "<string>",
      "input": {},
      "status": "SUCCESS",
      "data": "<unknown>",
      "creditsUsed": 123,
      "durationMs": 123,
      "error": "<string>",
      "events": [
        {
          "type": "navigation",
          "data": {},
          "ts": "2023-11-07T05:31:56Z"
        }
      ]
    }
  ],
  "totalCreditsUsed": 123,
  "status": "processing",
  "createdAt": "2023-11-07T05:31:56Z",
  "completedAt": "2023-11-07T05:31:56Z",
  "liveEvents": [
    [
      {
        "type": "navigation",
        "data": {},
        "ts": "2023-11-07T05:31:56Z"
      }
    ]
  ],
  "error": "<string>"
}
Fetch one run by id. Use this to poll an async submission, review a historical run, or pull the full per-step event timeline for debugging.

Overview

  • Method: GET
  • Path: /api/v1/browser-agents/{id}
  • Auth: same Authorization: Bearer YOUR_API_KEY as Run a Task
  • Scope: you can only fetch runs created with your own API key.

Path Parameters

NameTypeRequiredDescription
idstringRun id returned by POST /api/v1/browser-agents (a 24-char Mongo ObjectId).

Query Parameters

NameTypeDefaultDescription
includeEventsbooleanfalseWhen true, includes the full per-step event timeline on each TaskResult (see events) and adds a top-level liveEvents field for tasks that are still running. Payloads can be large — screenshots inflate them fast.

Response

Returns the same BatchResult shape produced by POST /api/v1/browser-agents. See Run a Task → Response Schemas for the field-by-field breakdown.

In-progress runs

While status === "processing":
  • results[i] holds a completed task when task i has finished, otherwise a synthesized pending stub with { url, instruction, input, status: "PENDING" } so your UI can always render the task row.
  • completed counts how many tasks have a real result (not stubs).
  • When includeEvents=true, liveEvents[i] holds the in-flight event stream for each still-running task. Completed tasks get liveEvents[i] = [].

Completed runs

When status === "completed" (or "failed"):
  • Every results[i] is a real TaskResult.
  • liveEvents is omitted (all timelines live on results[i].events when includeEvents=true).
  • completedAt is populated.

Example — polling an async run

curl https://api.pre.dev/api/v1/browser-agents/65f8a9d2c1e4b5a6f7e8d9c0 \
  -H "Authorization: Bearer $PREDEV_API_KEY"
{
  "id": "65f8a9d2c1e4b5a6f7e8d9c0",
  "total": 3,
  "completed": 2,
  "results": [
    {
      "url": "https://example.com",
      "instruction": "Extract the heading.",
      "status": "SUCCESS",
      "data": { "heading": "Example Domain" },
      "creditsUsed": 0.11,
      "durationMs": 4820
    },
    {
      "url": "https://news.ycombinator.com",
      "instruction": "Extract the top 5 story titles.",
      "status": "SUCCESS",
      "data": { "stories": ["...", "..."] },
      "creditsUsed": 0.18,
      "durationMs": 8132
    },
    {
      "url": "https://www.reddit.com/r/programming",
      "instruction": "Extract the top 5 post titles.",
      "status": "PENDING"
    }
  ],
  "totalCreditsUsed": 0.29,
  "status": "processing",
  "createdAt": "2026-04-16T18:22:10.224Z"
}

Example — full timeline for one task

curl "https://api.pre.dev/api/v1/browser-agents/65f8a9d2c1e4b5a6f7e8d9c0?includeEvents=true" \
  -H "Authorization: Bearer $PREDEV_API_KEY"
Each TaskResult now carries an events array, and while any task is still running liveEvents is populated too.
{
  "id": "65f8a9d2c1e4b5a6f7e8d9c0",
  "total": 1,
  "completed": 1,
  "status": "completed",
  "results": [
    {
      "url": "https://example.com",
      "status": "SUCCESS",
      "data": { "heading": "Example Domain" },
      "creditsUsed": 0.11,
      "durationMs": 4820,
      "events": [
        { "type": "navigation", "data": { "url": "https://example.com" } },
        { "type": "plan",       "data": { "reasoning": "The heading is the <h1>..." } },
        { "type": "screenshot", "data": { "url": "https://cdn.pre.dev/screenshots/..." } },
        { "type": "action",     "data": { "action": "extract", "selector": "h1" } },
        { "type": "validation", "data": { "passed": true } },
        { "type": "done",       "data": { "status": "SUCCESS" } }
      ]
    }
  ]
}

Event timeline

The events array records every step the agent took. Each event is { type, data, ts? }. Event types you’ll see:
TypeWhenNotable data fields
navigationAgent loaded a URLurl
planAgent reasoned about next stepsreasoning, steps
actionAgent performed an interactionaction (click/type/scroll/extract), selector
screenshotFrame capturedurl (CDN link)
validationOutput schema / success condition checkedpassed, errors
doneTask finishedstatus
errorTask erroredmessage
Internal fields (sandbox provider, LLM model, token counts) are stripped from events before they’re returned. You only see what your task did, not how we ran it.

Status Codes

CodeMeaning
200Run found. Body is the BatchResult.
400Malformed run id.
401Missing or invalid bearer token.
404Run not found, or not owned by this API key.

Polling Patterns

Python — poll until done

import time
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.pre.dev/api/v1/browser-agents"
HDR = {"Authorization": f"Bearer {API_KEY}"}


def wait_for_run(run_id: str, *, include_events: bool = False, poll_every: float = 5.0, timeout_s: float = 1800):
    deadline = time.time() + timeout_s
    while True:
        params = {"includeEvents": "true"} if include_events else None
        r = requests.get(f"{BASE}/{run_id}", headers=HDR, params=params)
        r.raise_for_status()
        run = r.json()
        if run["status"] in ("completed", "failed"):
            return run
        print(f"{run['completed']}/{run['total']} done")
        if time.time() > deadline:
            raise TimeoutError(f"run {run_id} still processing after {timeout_s}s")
        time.sleep(poll_every)


run = wait_for_run("65f8a9d2c1e4b5a6f7e8d9c0")
for r in run["results"]:
    print(r["status"], r.get("data"))

Node.js — poll with exponential backoff

const API_KEY = process.env.PREDEV_API_KEY;
const BASE = "https://api.pre.dev/api/v1/browser-agents";

async function waitForRun(id, { includeEvents = false, maxMs = 30 * 60_000 } = {}) {
  const deadline = Date.now() + maxMs;
  let delay = 1000;

  while (Date.now() < deadline) {
    const url = `${BASE}/${id}${includeEvents ? "?includeEvents=true" : ""}`;
    const res = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } });
    if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);

    const run = await res.json();
    if (run.status === "completed" || run.status === "failed") return run;

    await new Promise((r) => setTimeout(r, delay));
    delay = Math.min(delay * 1.5, 15_000);
  }
  throw new Error(`timed out waiting for run ${id}`);
}

const run = await waitForRun("65f8a9d2c1e4b5a6f7e8d9c0");
console.log(run.results.map((r) => r.data));
For interactive UIs use stream: true on the initial Run a Task request to skip polling entirely. Use GET /:id?includeEvents=true only to reconstruct timelines for historical runs.

Next: List Tasks

Paginate over every task submission your API key has created, filter by status.

Authorizations

Authorization
string
header
default:YOUR_API_KEY
required

API key for authentication. Get your API key from https://pre.dev/projects/playground (Solo) or https://pre.dev/enterprise/dashboard?page=api (Enterprise). Use format: Bearer YOUR_API_KEY

Path Parameters

id
string
required

Run id (24-char Mongo ObjectId).

Query Parameters

includeEvents
boolean
default:false

Include per-step event timelines. Payloads can be large — screenshots inflate them fast.

Response

Run result.

Run summary. The schema is named BatchResult for backwards compatibility with older clients.

id
string

Run id (24-char Mongo ObjectId).

total
integer

Total tasks in the run.

completed
integer

Number of tasks that have finished (any status).

results
object[]

Per-task results aligned by taskIndex. In-progress runs return PENDING stubs for tasks that haven't started; the stub has only url, instruction, input, and status: "PENDING".

totalCreditsUsed
number

Sum of credits billed across all tasks in the run.

status
enum<string>
Available options:
processing,
completed,
failed
createdAt
string<date-time>
completedAt
string<date-time>

Populated once status !== "processing".

liveEvents
object[][]

Only present when includeEvents=true on GET /:id. Per-task in-flight event streams for tasks that haven't yet finished. Aligned by index with results; completed tasks get an empty array.

error
string

Set only when status === "failed".