REST API · v1

One Bearer key, from goal to action.

Hand your agent the live web from your own stack: it drives any site you point it at and signs into the accounts you connect, on exactly the URL you pass. A small, versioned surface under /api/v1 — run a goal, queue it, or replay a compiled skill.

54 endpointsOpenAPI 3.1Bearer auth

The first call

Three lines from your stack.

No SDK required: one POST against https://twin-browser.com/api/v1 is the whole integration. A solved goal settles at 10 credits, and the run id in the response is the handle for the recording and the audit record.

run.sh — request + responsebash
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" }
  }'

# HTTP/2 200
# {
#   "success": true,
#   "path": [ ... ],            <- the action path that solved it
#   "runId": "run_...",         <- fetch the recording or the audit record
#   "credits_charged": 10
# }
run.tstypescript
// One key, one POST. Base URL: https://twin-browser.com/api/v1
const res = await fetch('https://twin-browser.com/api/v1/run', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TWIN_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://app.acme.com/invoices',
    prompt: 'export last month as CSV',
    success: { kind: 'urlIncludes', value: '/exports' },
  }),
});

const run = await res.json();
run.success;          // true
run.runId;            // stable id — recording + audit record
run.credits_charged;  // what this call actually cost

How a call flows

Authenticated, observable, settled.

Every call runs the same four stages — and the third one is where the cost falls away.

  1. Authenticate

    Every call carries Authorization: Bearer with a per-tenant key. Default-deny RLS scopes every read and write to your tenant; an invalid key fails closed with 401.

  2. Observe the target

    Twin loads the URL you passed and serializes it into a compact, numerically-indexed map of interactive elements — token-efficient state, not raw HTML.

  3. Replay or plan

    The semantic cache fuzzy-matches the request to a compiled skill. On a hit it replays deterministically with zero LLM calls; on a miss the planner discovers a path and compiles it.

  4. Settle & audit

    Credits settle on the first terminal read — failed, cancelled, or unsolved actions refund in full. The goal, path, target, and key are written to the audit log.

Endpoints

54 endpoints, printed in full.

Not a feature list — the surface itself, rendered from the same OpenAPI document served at GET /api/v1/openapi. If an endpoint ships, it appears here on the next build.

Every endpoint in the Twin Browser /api/v1 surface, grouped by family.
MethodEndpointWhat it does
Runs & live control
POST/api/v1/runRun a goal synchronously on an authorized target (~10 credits).
POST/api/v1/liveRun a goal and stream the LIVE browser view back as Server-Sent Events (~10 credits).
POST/api/v1/live/resumeHand a 2FA code (or cancel) to a live run holding on an await-user step.
GET/api/v1/runsList this tenant's runs (newest first, paginated).
GET/api/v1/runs/{id}Read a single run: status, success, masked action path, credits, video, timestamps.
POST/api/v1/runs/{id}/resumeContinue a paused (HITL) sync run after an out-of-band approval.
POST/api/v1/runs/{id}/inputDrive a paused run's browser by hand (click / type / key / scroll / goto).
GET/api/v1/runs/{id}/streamWatch a paused run's browser live (SSE screencast) so you can drive it.
GET/api/v1/runs/{id}/videoStream a run's recorded video (only if the run was created with record:true).
POST/api/v1/agentdeprecatedDEPRECATED alias for POST /run with {"stealth":true} — prefer that. Forces the full anti-detection stack.
Semantic cache & skills
POST/api/v1/dispatchSemantic cache: match to a compiled skill (hit) or compile + cache (miss).
GET/api/v1/skillsList this tenant's compiled skills.
POST/api/v1/skillsCompile a skill — discover + minimize (~50 credits).
POST/api/v1/skills/{name}/runDeterministically replay a compiled skill — no LLM (~1 credit).
GET/api/v1/librarySearch the cross-tenant shared skill corpus — metadata only (free).
GET/api/v1/cache/statsSemantic-cache analytics for this tenant — hit rate + credits saved (free, no charge).
GET/api/v1/templatesList the extraction-template catalog used by /extract and /etl (public, no key).
Async jobs
GET/api/v1/jobsList this tenant's recent async jobs.
POST/api/v1/jobsSubmit a goal as an async job (~10 credits). Returns 202 { jobId }.
GET/api/v1/jobs/{id}Poll an async job; settles credits on first terminal status.
GET/api/v1/jobs/{id}/streamStream an async job's status as Server-Sent Events (an alternative to polling).
POST/api/v1/jobs/{id}/cancelCancel a running async job — full refund of the reserved credits.
Data tools
POST/api/v1/searchWeb search across blended sources (Brave web/discussions/news/faq + Hacker News, deduped, each result tagged with source). Shallow (default): sync ranked results (~3 cr) + optional fetch (+1 cr/page). Deep (depth:"deep"): async job, scrapes top N (3 cr + 5 cr/page), returns 202 { jobId }.
POST/api/v1/extractExtract structured JSON from a page with an LLM (metered, ~5-credit floor).
POST/api/v1/screenshotCapture a single page as a PNG (flat ~1 credit, no LLM cost). Waits for the page to be visually finished — fonts, images, entrance animations, pixel stability — before capturing.
POST/api/v1/mapDiscover all URLs of a site fast — sitemap + robots + shallow link scan (flat ~2 credits, no LLM).
POST/api/v1/crawlCrawl an entire site as an async job — billed per page (~3 credits/page). Returns 202 { jobId }.
POST/api/v1/etlGeneral ETL: extract → transform (clean + optional schema) → chunk → embed → load into the queryable content store.
POST/api/v1/etl/querySemantic search over content ingested via /etl — top-k similar chunks with source url/title (flat 1 credit, no LLM).
Monitors
GET/api/v1/monitorsList this tenant's monitors (secrets excluded).
POST/api/v1/monitorsCreate a monitor that watches a page on a schedule and pushes a signed webhook on change.
GET/api/v1/monitors/{id}Read a single monitor (secrets excluded).
PATCH/api/v1/monitors/{id}Update / pause / resume a monitor (active, interval, callback, selector, watch spec).
DELETE/api/v1/monitors/{id}Delete a monitor and its check history.
GET/api/v1/monitors/{id}/historyA monitor's recent check history (changed/unchanged/error + value excerpts).
Sessions & credentials
GET/api/v1/connect/sessionsList connect links and whether each sign-in was completed.
POST/api/v1/connect/sessionsMint a link that lets a HUMAN sign into a site, so later runs are already logged in.
POST/api/v1/sessions/importImport a browser session captured on the user’s OWN machine (the capture extension).
GET/api/v1/accountsWhich logins this tenant already has — metadata only, never a credential.
GET/api/v1/secretsList this tenant's stored secret NAMES (write-only vault — values are never returned). Free.
POST/api/v1/secretsStore (encrypt) a named secret for this tenant, referenceable in prompts as {{secret:NAME}}. Free.
DELETE/api/v1/secrets/{name}Delete a stored secret by name for this tenant. Free.
GET/api/v1/email-inboxList the connected IMAP inboxes used to auto-resolve emailed 2FA codes (host/user only).
POST/api/v1/email-inboxConnect an IMAP inbox so sign-in runs auto-fill the emailed 2FA code (no HITL pause).
DELETE/api/v1/email-inboxDisconnect a stored IMAP inbox by name.
Page intelligence & anti-bot
POST/api/v1/observeSerialize a page into indexed DOM state without acting (~1 credit).
POST/api/v1/solve-captchaSolve a captcha blocking an in-flight session (~5 credits, charged only on success).
Platform & billing
GET/api/v1/tenantsReseller: list your subtenants with balances and what they cost you.
POST/api/v1/tenantsReseller: create a subtenant under your account and mint its API key.
GET/api/v1/pricingPublic credit rate card (no API key required).
Everything else
GET/api/v1/siteWhat we already know about a host — its anti-bot wall, your auth state there, and the run configuration both imply. Free.
GET/api/v1/warningsList this tenant's open warnings — the general notifications surface. Free.
POST/api/v1/warnings/{id}/ackAcknowledge (dismiss) one warning by id. Free.
POST/api/v1/downloadFetch an authorized asset's raw bytes — a logo, image, PDF, or other document (flat ~1 credit, no LLM cost).

Request fields, success-condition specs, response codes and error shapes are in the full endpoint reference.

Reading the cache

The outcome is a field, not a guess.

Every /dispatch response names how it was served and what it cost, in the body you already parsed. A drifted skill and an unsolved goal both come back as a 502 with the reservation refunded in full.

The mode values a POST /api/v1/dispatch response can return.
modeCreditsMeaning
cache-hit2A skill compiled for this host matched. Blind replay, no LLM in the loop.
cache-adapt5A near-match from the shared corpus seeded the run; only the delta was explored.
cache-miss-compiled10Nothing matched. The planner discovered a path and cached it for next time.
cache-hit-failedrefundedThe cached path no longer reaches the goal — drift. Returned as 502, fully refunded.
cache-miss-failedrefundedDiscovery could not solve the goal. Returned as 502, fully refunded.
dispatch.shbash
# The cheap path. /dispatch matches the goal against skills already
# compiled for this host, and compiles one when nothing matches.
curl -X POST https://twin-browser.com/api/v1/dispatch \
  -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" } }'

# HIT   { "mode": "cache-hit",           "skill": "acme-export", "version": 3,
#         "success": true, "credits_charged": 2 }
# ADAPT { "mode": "cache-adapt",         "source": "acme-export",
#         "success": true, "credits_charged": 5 }
# MISS  { "mode": "cache-miss-compiled", "skill": "acme-export", "version": 1,
#         "success": true, "credits_charged": 10 }
skills.shbash
# Compile a goal into a reusable, deterministic skill (discover + minimize).
# "as" names it; the body is { url, prompt } or { target, goal }.
curl -X POST https://twin-browser.com/api/v1/skills \
  -H "Authorization: Bearer ab_live_…" -H "Content-Type: application/json" \
  -d '{ "url": "https://app.acme.com/invoices",
        "prompt": "export last month as CSV", "as": "acme-export" }'
# -> { "name": "acme-export", "version": 1, "steps": 6,
#      "runId": "run_...", "credits_charged": 50 }

# List your compiled skills.
curl https://twin-browser.com/api/v1/skills -H "Authorization: Bearer ab_live_…"
# -> { "skills": [ ... ] }

# Replay one by name — no LLM in the loop. Takes "target".
curl -X POST https://twin-browser.com/api/v1/skills/acme-export/run \
  -H "Authorization: Bearer ab_live_…" -H "Content-Type: application/json" \
  -d '{ "target": "https://app.acme.com/invoices" }'
# -> { "success": true, "credits_charged": 1 }

Operating the API

Limits, discovery, and the rate card.

Rate limits

Applied per tenant. Over the limit returns 429 with a Retry-After header — back off and retry. Higher tiers raise limits and replay throughput.

OpenAPI + rate card

The surface is an OpenAPI 3.1 document at /api/v1/openapi for client generation and agent discovery, and the live rate card is JSON at /api/v1/pricing.

Auth & audit

Per-tenant keys, default-deny RLS, and an audit log on every call. The target URL is the authorization signal — see the security page.

FAQ

API, answered

How do I authenticate?
Every request carries an Authorization: Bearer header with a per-tenant API key. Keys are shown once at creation and stored only as a hash. Create one in the dashboard after signing up and keep it server-side.
How do I tell whether a call hit the cache?
POST /api/v1/dispatch returns a mode field on every response: cache-hit (a compiled skill replayed), cache-adapt (a corpus near-match seeded the run), or cache-miss-compiled (the planner discovered and cached a path). The body also carries skill, version, steps, runId and credits_charged, so the cache outcome and the exact cost of a call are both in the response you already parsed.
Is there an OpenAPI spec?
Yes — an OpenAPI 3.1 document served at GET /api/v1/openapi, and it is the same document this page and the reference at /docs/api are rendered from, so the three cannot drift. The public rate card is JSON at GET /api/v1/pricing.
How are rate limits enforced?
Limits are applied per tenant. When you exceed your limit the API returns 429 with a Retry-After header; back off and retry. High-volume and Enterprise plans get raised limits and priority replay throughput.
What does a call cost?
Costs are in credits: a solved goal is 10, a compile is 50, a deterministic replay is 1, and a dispatch is 2 on a cache hit against 10 on a miss. Each call is billed the higher of the flat price and the metered cost of that run. Failed, cancelled, or unsolved actions are fully refunded.

Prefer tools over endpoints?

The same engine is an MCP server for Claude and Cursor, and a one-line adapter for LangChain and AutoGen.