docs · rest api
REST API
Base URL https://gw.flatbrowser.com. Every endpoint except /healthz needs your API key (Authorization: Bearer …, or ?token=). Bodies are JSON, at most 256 KB on the native /v1 routes. Errors use one envelope, described in errors & limits.
Endpoints
| endpoint | returns |
|---|---|
POST /v1/sessions | a session you attach to over WebSocket |
GET /v1/sessions | your active sessions |
DELETE /v1/sessions/:id | ends a session |
POST /v1/screenshot | image/png |
POST /v1/pdf | application/pdf |
POST /v1/content | JSON {"html": …} |
POST /v1/scrape | JSON {"data": […]} |
GET /json/version | the CDP discovery document |
GET /healthz | gateway health (no key needed) |
Each screenshot, PDF, content or scrape call starts its own short session in one of your workers, so it uses one concurrency slot while it runs and frees it when it returns. Nothing it produces is stored: the image, PDF or HTML is streamed back in the response and gone from our side once sent.
Sessions
POST /v1/sessions
Creates a session that outlives connections (see sessions). All body fields are optional; unknown fields are refused.
| field | type | meaning |
|---|---|---|
idleTimeoutMs | integer | end after this long with no client attached (default 300000) |
maxDurationMs | integer | total lifetime cap (default and maximum 43200000 = 12 h) |
proxyUrl | string | your upstream proxy — see proxies |
locale | string | BCP-47 browser locale, e.g. de-DE (navigator.language, Accept-Language) |
timezone | string | IANA timezone, e.g. Europe/Berlin |
args | string[] | extra Chromium flags from the allowlist (max 32) |
The response’s connectUrl deliberately has no key in it; append ?token=<your key> when you connect.
curl -X POST https://gw.flatbrowser.com/v1/sessions -H 'Authorization: Bearer flat_live_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"idleTimeoutMs":300000,"proxyUrl":"http://user:pass@proxy.example.net:8000","locale":"de-DE","timezone":"Europe/Berlin"}'
# → 201 {"id":"3f0c…","connectUrl":"wss://gw.flatbrowser.com/session/3f0c…","wsPath":"/session/3f0c…"}
curl https://gw.flatbrowser.com/v1/sessions -H 'Authorization: Bearer flat_live_YOUR_KEY'
# → {"sessions":[{"id":"3f0c…","status":"active","source":"rest","workerId":"…","startedAt":"…"}]}
curl -X DELETE https://gw.flatbrowser.com/v1/sessions/3f0c… -H 'Authorization: Bearer flat_live_YOUR_KEY'
# → {"ok":true}POST /v1/screenshot
url(required): a public http(s) URLfullPage: capture the whole scrollable page (default false)width/height: viewport in CSS pixels (default 1280 × 720, max 7680 × 4320)waitUntil:load(default),domcontentloaded,networkidleorcommit
curl -X POST https://gw.flatbrowser.com/v1/screenshot \
-H 'Authorization: Bearer flat_live_YOUR_KEY' -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","fullPage":true,"width":1440,"height":900}' \
-o page.pngPOST /v1/pdf
url(required)format: Letter, Legal, Tabloid, Ledger or A0–A6 (default A4)waitUntil:load(default),domcontentloaded,networkidleorcommit
curl -X POST https://gw.flatbrowser.com/v1/pdf \
-H 'Authorization: Bearer flat_live_YOUR_KEY' -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","format":"A4","waitUntil":"networkidle"}' \
-o page.pdfPOST /v1/content
The rendered page’s HTML after waitUntil, as JSON. The Browserless-style alias POST /content returns it as text/html instead.
curl -X POST https://gw.flatbrowser.com/v1/content \
-H 'Authorization: Bearer flat_live_YOUR_KEY' -H 'Content-Type: application/json' \
-d '{"url":"https://example.com"}'
# → {"html":"<!DOCTYPE html><html>…"}POST /v1/scrape
Text and inner HTML of every element matching each selector you send (up to 32 selectors, 2,000 matches each). A selector’s optional timeout (max 30000 ms) waits for it to appear; a miss is an empty result, not an error. An invalid CSS selector is a 400. You choose the selectors — we ship no site-specific scrapers.
curl -X POST https://gw.flatbrowser.com/v1/scrape \
-H 'Authorization: Bearer flat_live_YOUR_KEY' -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","elements":[{"selector":"h1"},{"selector":"a","timeout":2000}]}'
# → {"data":[{"selector":"h1","results":[{"text":"Example Domain","html":"Example Domain"}]}, …]}Query parameters on session-creating calls
POST /v1/sessions and the four actions also read the same query parameters as the WebSocket URL: proxy, timeout, queueTimeout, locale, timezone, launch and --chromium-flag parameters. On an action, timeout is the guard for the whole call (default 60 s, max 180 s). Unknown parameters are refused with a 400; parameters we accept but do not act on are listed, by name only, in the X-Flatbrowser-Ignored-Params response header. The full list is on the compatibility page.
Browserless-style aliases
POST /screenshot, /pdf, /content and /scrape (also under /chromium/ and /chrome/) accept Browserless-shaped bodies — for example html instead of url, gotoOptions, options, viewport and waitForSelector — and run on the same implementation as /v1. What is and is not supported there is listed in the migration guide.
Which URLs you can open
- Only public http(s) hosts. Private, loopback and cloud-metadata addresses are refused, and so are hostnames that resolve to them.
- Hostnames on our abuse blocklist are refused with 403
target_blockedbefore a slot is used. Inside CDP sessions the same hostnames do not resolve (net::ERR_NAME_NOT_RESOLVED). - A navigation that fails on the target side (DNS, TLS, connection refused) is a 424 with the browser’s error in the message.