Getting started
Twin Browser is a browser execution layer for agents: you authorize a run with a key and a target URL, the engine does the work in a real browser, and repeated work gets cheap through the semantic cache. Everything below is plain REST under https://twin-browser.com/api/v1; the API reference lists every endpoint, and GET /api/v1/openapi is the same contract machine-readable.
Authentication
Every call carries Authorization: Bearer ab_live_…. Keys are per-tenant, minted in the dashboard under Keys & Secrets (the full key is shown once, at creation), and can carry scopes. The tenant is always derived from the key — never from the request body — and every run is scoped to it, metered in credits, and written to the audit log. Keys can be revoked at any time.
Your first run
A run is three things: a url (the authorization signal — you run against targets you name), a natural-language prompt, and a structured success condition the engine must satisfy for the run to count. The response carries the verified action path and exactly what was charged.
# Base URL: https://twin-browser.com/api/v1
# Auth: a per-tenant Bearer key (dashboard → Keys & Secrets; shown once).
curl https://twin-browser.com/api/v1/run \
-H "Authorization: Bearer ab_live_…" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.acme.com/invoices",
"prompt": "export last month as CSV",
"success": { "kind": "urlIncludes", "value": "/exports" }
}'
# → 200 { "success": true, "path": [ … ], "credits_charged": 10, "engineRev": "…" }
# Anything you will ask twice: same body to /dispatch — the semantic cache
# matches re-phrased requests to compiled skills and replays with no LLM:
# HIT ~2 credits · MISS ~10 (compiles + caches for next time)
# Or manage the skill explicitly:
# POST /skills { "target": "…", "goal": "…", "as": "acme-export" }
# POST /skills/acme-export/run → deterministic replay, ~1 creditPick the right endpoint
The full shapes are in the reference — this is the routing table.
POST /runsync · ~10 crOne-shot goal, planned live. Sign-in runs park (resumable) on 2FA walls by default.POST /dispatchsync · ~2–10 crSame body as /run, fronted by the semantic cache. Default for anything you will ask twice.POST /liveSSE · ~10 crSame body, but the response is a live screencast stream (meta → frame* → result), resumable mid-run.POST /jobsasync · 202Background execution of the same body: poll, stream status, or get an HMAC-signed webhook.POST /skills + /skills/{name}/runsync · ~50 / ~1 crCompile a goal once into a named skill, then replay it deterministically with no LLM.POST /extractsync · ~5 crStructured JSON out of one page (fields or schema); free + deterministic when a template matches.POST /search · /map · /crawl · /screenshotdata toolsBlended web search, site URL discovery, whole-site background crawling, page screenshots.POST /etl + /etl/querypipelineScrape into a named, embedded collection; query it semantically.POST /monitorsstandingWatch a page on a cadence; HMAC-signed callback on change.POST /connect/sessionssessionsOne-time link your end-user opens to sign in by hand — the session is captured, the password never stored.POST /secrets · GET /accountscredentialsStore credentials write-only ({{secret:NAME}}); discover which login labels already exist per host.
Credits & metering
Everything is prepaid in credits. A run reserves its ceiling up front and settles on the terminal result — a failed or empty run refunds the reserve. Charges are the higher of a flat per-action floor (run ~10, dispatch HIT ~2, skill replay ~1, extract ~5) and metered passthrough cost, and every response states credits_charged. The live rate card is at GET /pricing (no key needed) and rendered in the guide. Balance and auto top-up live in the dashboard under Settings → Billing.
Errors & result codes
Transport-level errors are conventional; the interesting signals ride inside 200 results.
400Malformed body — e.g. a free-text goal in the named { target, goal } shape, or a bad success spec.401Missing or invalid API key.402Insufficient credits — top up or enable auto top-up.403Unauthorized target, missing scope, or a plan gate (code: "plan_required" — e.g. stealth runs need Pro).422Nothing to act on — e.g. /extract with no schema, fields, or matching template.429The per-account cadence governor: too many runs against the same account/host in the window. Honor Retry-After.
Inside a completed run, watch for code:
status: "paused"HITLA sign-in run parked on a 2FA/approval wall. Resume with POST /runs/{id}/resume + a code, drive it via /runs/{id}/input, or hand it off with a connect link. Opt out with hitl:false.code: "credential_missing"+ missingSecretThe run needed a credential you have not stored — store it via POST /secrets, or send the user through POST /connect/sessions.code: "connect_required"+ connectUrlAutomation cannot pass this wall. A ready one-time connect link is minted for you — hand it to your end-user; later runs restore the captured session.
The four surfaces
The same authenticated engine is reachable four ways: REST (this reference), MCP — npx -y twin-browser-mcp exposes 31 tools to Cursor, Claude Desktop, Claude Code, or Cline (setup), the dashboard console (every API mode, interactive, with live streaming), and framework adapters — makeTwinBrowserTools() for LangChain / AutoGen. Agents can also read /llms.txt and /api/v1/openapi directly.
Go deeper
API reference/docs/apiEvery endpoint, field, parameter, and response code — generated from the OpenAPI spec.Guide/docs/developThe developer loop end-to-end: first run → cache → extraction → live view → HITL → connect links → rates.MCP server/docs/mcpWire the engine into your IDE or agent in two minutes; all 31 tools listed.Lexicon/docs/lexiconEvery term the API, dashboard, and docs share — defined once, linkable.