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, onwss://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
/Get the project and plan entitlementsauthenticatedv1/ project - 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
/Get the current identity and effective scopesauthenticatedv1/ me - 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
/Create or enqueue a browser sessionsessions:writev1/ sessions 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.
{ "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
/List project sessionssessions:readv1/ sessions - 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
/Get current session statesessions:readv1/ sessions/ {sessionId} - 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
/Refresh idle deadline and checkpoint usagesessions:writev1/ sessions/ {sessionId}/ heartbeat - 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
/Extend a running sessionsessions:writev1/ 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
/Change location for a pending ephemeral sessionsessions:writev1/ sessions/ {sessionId}/ proxy/ retarget Only valid before a proxy lease is assigned. The queue deadline is preserved.
{ "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
/Retry a failed ephemeral sessionsessions:writev1/ sessions/ {sessionId}/ retry 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.
{ "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
/Report a proxy tunnel failure from a running sessionsessions:writev1/ sessions/ {sessionId}/ proxy-failures 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.
{ "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
/Cancel pending or stop running sessionsessions:writev1/ sessions/ {sessionId} - 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
/Create a profile or save a running sessionprofiles:writev1/ profiles 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.
{ "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
/List active profilesprofiles:readv1/ profiles - 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
/Schedule profile and snapshot deletionprofiles:writev1/ profiles/ {profileId} - 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
/List assignable city/pool capacityany browser write scopev1/ proxy-locations 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
/List verified relocation targetsany browser write scope or labs:proxyv1/ proxy-relocation-locations - 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
/Rotate or replace a running ephemeral session's random proxysessions:writev1/ sessions/ {sessionId}/ proxy/ rotate 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
/Relocate a running lab session to a verified citylabs:proxyv1/ sessions/ {sessionId}/ proxy/ relocate 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.
{ "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
/Queue a Playwright or Scrapling browser job (preview)jobs:writev1/ jobs 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.
{ "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
/List asynchronous jobs (preview)jobs:readv1/ jobs - 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
/Get live job state, result, and artifacts (preview)jobs:readv1/ jobs/ {jobId} - 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
/Cancel a queued or running job (preview)jobs:writev1/ jobs/ {jobId} - 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
/Download an authenticated job artifact (preview)jobs:readv1/ artifacts/ {artifactId} - 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
/Get aggregate project usageusage:readv1/ usage - 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
/Get per-session usage and cost statementusage:readv1/ usage/ statement?from={RFC3339}&to={RFC3339} - 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
/Get subscription and prepaid balancebilling:readv1/ billing - 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
/List credits, debits, refunds, and adjustmentsbilling:readv1/ billing/ transactions - 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
/Create a hosted prepaid top-upbilling:writev1/ 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
/Create a hosted subscription checkoutbilling:writev1/ 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
/Open the Stripe customer portalbilling:writev1/ billing/ portal - 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
/Create a scoped API keykeys:writev1/ api-keys The plaintext secret is returned once. Rotation supports overlapping 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
/List prefixes, scopes, expiry, and last usekeys:writev1/ api-keys - 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
/Replace key scopes without changing its secretkeys:writev1/ api-keys/ {keyId} - 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
/Revoke an API keykeys:writev1/ api-keys/ {keyId} - 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.