Docs

Start a session over REST. Drive it with Playwright.

One POST creates a session in its own microVM. Playwright connects with connectOverCDP, and a DELETE stops it. There is no SDK to install.

REST API
https://api.headlessfleet.com
Authentication
Authorization: Bearer $HEADLESSFLEET_API_KEY
CDP
Each running session’s cdp_url, on wss://connect.headlessfleet.com

Quickstart

Your first session

Set HEADLESSFLEET_API_KEY to a key from the dashboard, then run one of these. The Node.js and Python samples create a session, wait while it starts, open a page and stop the session. The cURL sample makes the same API calls.

import { chromium } from "playwright";

const api = "https://api.headlessfleet.com/v1/sessions";
const headers = {
  Authorization: `Bearer ${process.env.HEADLESSFLEET_API_KEY}`,
  "Content-Type": "application/json",
};

// Sends one API request and returns the JSON body. Throws on an error status.
async function call(url, init = {}) {
  const response = await fetch(url, { ...init, headers });
  const text = await response.text();
  if (!response.ok) throw new Error(`${response.status}: ${text}`);
  return JSON.parse(text);
}

// 201: running within 3 s. 202: pending or starting, so poll every 2 s.
let session = await call(api, {
  method: "POST",
  body: JSON.stringify({ timeout_seconds: 600, proxy: { country: "US" } }),
});
const url = `${api}/${session.id}`;
try {
  while (["pending", "starting"].includes(session.status)) {
    await new Promise((done) => setTimeout(done, 2000));
    session = await call(url);
  }
  if (session.status !== "running") {
    throw new Error(`Session ${session.status}: ${session.failure_code}`);
  }
  const browser = await chromium.connectOverCDP(session.cdp_url);
  const context = browser.contexts()[0];
  const page = context.pages()[0] ?? await context.newPage();
  await page.goto("https://example.com");
  console.log(await page.title());
  await browser.close();
} finally {
  // The session keeps running after Playwright disconnects. Stop it here.
  await fetch(url, { method: "DELETE", headers });
}

Node 18+ and npm install playwright. No SDK.

  • Queue-aware admission

    201 means ready. 202 includes Location and a pending or starting session. Poll until running or terminal.

  • Credential safety

    CDP URLs are credentials that work until the session ends. Never log or send them through callbacks or support channels.

  • Proxy identity

    Random sessions release their pool lease on close, then reconnect through an eligible slot. Saved profiles retain their profile and endpoint affinity across restores.

  • Idle timeout and metering

    CDP messages and live-view frames or input keep a running session from idling out; WebSocket pings do not. The idle timeout is at most 600 seconds, so heartbeat a session that goes longer without traffic, for example on a slow model call. Usage checkpoints are cumulative and sequenced, so retries never double-charge.

Reference

Endpoints

The main customer routes and the API key scope each one needs. Routes that need a labs scope are restricted. The OpenAPI file lists every route.

34 endpoints

  • GET/v1/projectGet the project and plan entitlementsauthenticated
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/meGet the current identity and effective scopesauthenticated
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessionsCreate or enqueue a browser sessionsessions:write

    Returns 201 when the session is running within the 3-second synchronous budget, or 202 with Location while it is pending or starting. Returns 402 prepaid_credit_required once this month's included browser time or data is used and the prepaid balance is not positive; add credit with POST /v1/billing/topups. Returns 429 too_many_queued_sessions while the project already has twice its max_concurrent_sessions pending; nothing is queued, and each POST /v1/session-batches item past that limit reports the same 429 in its own result. idle_timeout_seconds is 30 to 600 and no longer than timeout_seconds (400 invalid_idle_timeout); to wait longer without traffic, for example on a slow model call, send POST /v1/sessions/{sessionId}/heartbeat. Shared proxy endpoints allow one active lease per API key while different keys may reuse an endpoint up to its operator cap. Keys that also hold labs:browser may submit audited lab_overrides; internal runtime selectors and provider credentials remain excluded.

    POST /v1/sessions
    {
      "timeout_seconds": 600,
      "idle_timeout_seconds": 120,
      "queue_timeout_seconds": 120,
      "display_mode": "headless",
      "automation": { "mode": "standard_cdp" },
      "proxy": {
        "country": "US",
        "region": "TX",
        "city": "Dallas",
        "mode": "random",
        "pool": "shared"
      }
    }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/sessionsList project sessionssessions:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/sessions/{sessionId}Get current session statesessions:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/heartbeatRefresh idle deadline and checkpoint usagesessions:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/extendExtend a running sessionsessions:write
    POST /v1/sessions/{sessionId}/extend
    { "timeout_seconds": 900 }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/proxy/retargetChange location for a pending ephemeral sessionsessions:write

    Only valid before a proxy lease is assigned. The queue deadline is preserved.

    POST /v1/sessions/{sessionId}/proxy/retarget
    { "country": "US", "region": "AZ", "city": "Phoenix", "mode": "random", "pool": "shared" }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/retryRetry a failed ephemeral sessionsessions:write

    Omit proxy to inherit the failed session's resolved location, carrier, and pool with a new random allocation. If supplied, proxy must be a complete advertised target.

    POST /v1/sessions/{sessionId}/retry
    {
      "queue_timeout_seconds": 120
    }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/proxy-failuresReport a proxy tunnel failure from a running sessionsessions:write

    For an ephemeral random-proxy session, the report asks our mobile proxy network to relocate the assigned proxy to a provider-selected random location, verifies and records the resulting location/timezone/carrier, and does not apply a health cooldown. Stop the affected session and retry it for another allocation.

    POST /v1/sessions/{sessionId}/proxy-failures
    { "failure_code": "tunnel_connection_failed" }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • DELETE/v1/sessions/{sessionId}Cancel pending or stop running sessionsessions:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/profilesCreate a profile or save a running sessionprofiles:write

    Provide session_id and omit proxy to convert a running ephemeral session into a profile writer. Stop it normally to commit the encrypted snapshot. Profiles retain their exact endpoint, location, and carrier across restores.

    POST /v1/profiles
    {
      "name": "Checkout QA",
      "session_id": "ses_..."
    }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/profilesList active profilesprofiles:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • DELETE/v1/profiles/{profileId}Schedule profile and snapshot deletionprofiles:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/proxy-locationsList assignable city/pool capacityany browser write scope

    Shows aggregate free, active, sticky-reserved, rotation, health, and usage-blocked capacity without endpoint or tenant identity.

    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/proxy-relocation-locationsList verified relocation targetsany browser write scope or labs:proxy
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/proxy/rotateRotate or replace a running ephemeral session's random proxysessions:write

    For a dedicated session, connects an idle proxy if needed and changes the IP on its modem; a change not confirmed in time returns 202 with status pending. For a shared session, switches the browser to a different shared endpoint with the same country, region, city, carrier, and pool; other API keys on the old endpoint are unaffected. Closing a session releases the lease; the next connection is assigned from its requested pool. Saved profiles' sticky proxies cannot be rotated (409 random_proxy_required).

    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/sessions/{sessionId}/proxy/relocateRelocate a running lab session to a verified citylabs:proxy

    Restricted to trusted proxy-lab keys and dedicated sessions. Select an exact target from /v1/proxy-relocation-locations; carrier is optional. Confirmed changes return 200 and pending provider changes return 202; a location without free capacity returns 409 proxy_location_at_capacity.

    POST /v1/sessions/{sessionId}/proxy/relocate
    { "country": "US", "region": "TX", "city": "Dallas" }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/jobsQueue a Playwright or Scrapling browser job (preview)jobs:write

    Jobs are in preview and may change. engine defaults to playwright. The Scrapling engines run bounded extraction through the same isolated session, proxy, metering, and teardown path; the internal Scrapling service and token are never exposed.

    POST /v1/jobs
    {
      "url": "https://example.com",
      "engine": "scrapling_dynamic",
      "extract": [{ "name": "title", "selector": "h1" }],
      "include": "text",
      "network_idle": true,
      "timeout_seconds": 120,
      "proxy": { "country": "US", "region": "AZ", "city": "Phoenix", "mode": "random", "pool": "shared" }
    }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/jobsList asynchronous jobs (preview)jobs:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/jobs/{jobId}Get live job state, result, and artifacts (preview)jobs:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • DELETE/v1/jobs/{jobId}Cancel a queued or running job (preview)jobs:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/artifacts/{artifactId}Download an authenticated job artifact (preview)jobs:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/usageGet aggregate project usageusage:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/usage/statement?from={RFC3339}&to={RFC3339}Get per-session usage and cost statementusage:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/billingGet subscription and prepaid balancebilling:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/billing/transactionsList credits, debits, refunds, and adjustmentsbilling:read
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/billing/topupsCreate a hosted prepaid top-upbilling:write
    POST /v1/billing/topups
    { "amount_micros": 25000000 }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/billing/checkoutCreate a hosted subscription checkoutbilling:write
    POST /v1/billing/checkout
    { "plan": "growth" }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/billing/portalOpen the Stripe customer portalbilling:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • POST/v1/api-keysCreate a scoped API keykeys:write

    The plaintext secret is returned once. Rotation supports overlapping keys.

    POST /v1/api-keys
    {
      "name": "Production agent",
      "scopes": ["sessions:read", "sessions:write", "jobs:read", "jobs:write", "usage:read"]
    }
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • GET/v1/api-keysList prefixes, scopes, expiry, and last usekeys:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • PATCH/v1/api-keys/{keyId}Replace key scopes without changing its secretkeys:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.
  • DELETE/v1/api-keys/{keyId}Revoke an API keykeys:write
    • 2xx Success
    • 400 Invalid request
    • 401/403 Authentication or scope
    • 402 Prepaid credit required
    • 429 Rate limited, or the project's queue is full
    • 5xx Server error. Check before you retry a POST.