{ "openapi": "3.0.3", "info": { "title": "camofox-browser", "version": "1.13.1", "description": "Anti-detection browser automation server for AI agents. Accessibility snapshots, element refs, session isolation, cookie import, proxy rotation, and structured logs.", "license": { "name": "MIT", "url": "https://opensource.org/licenses/MIT" }, "contact": { "name": "Jo Inc", "url": "https://askjo.ai", "email": "oss@askjo.ai" } }, "servers": [ { "url": "http://localhost:9377", "description": "Local development" } ], "tags": [ { "name": "System", "description": "Server health, metrics, and status." }, { "name": "Tabs", "description": "Create, list, inspect, and destroy browser tabs." }, { "name": "Navigation", "description": "Navigate tabs to URLs or via search macros." }, { "name": "Interaction", "description": "Click, type, scroll, press keys, evaluate JS." }, { "name": "Content", "description": "Accessibility snapshots, screenshots, links, images, downloads." }, { "name": "Sessions", "description": "Per-user session state: cookies, teardown." }, { "name": "Browser", "description": "Global browser lifecycle (start/stop)." }, { "name": "Legacy", "description": "OpenClaw-compatible endpoints (deprecated)." } ], "components": { "securitySchemes": { "BearerAuth": { "type": "http", "scheme": "bearer", "description": "Bearer token matching CAMOFOX_API_KEY (per-route auth for sensitive endpoints like cookie import and traces)." }, "AccessKeyAuth": { "type": "http", "scheme": "bearer", "description": "Bearer token matching CAMOFOX_ACCESS_KEY. When set, gates all routes except /health, cookie import, and /stop. Acts as a superkey -- also accepted by endpoints that normally require CAMOFOX_API_KEY." } }, "schemas": { "Error": { "type": "object", "required": [ "error" ], "properties": { "error": { "type": "string" } } } } }, "paths": { "/sessions/{userId}/cookies": { "post": { "tags": [ "Sessions" ], "summary": "Import cookies into a user session", "description": "Import cookies for authenticated browsing. Requires BearerAuth in production.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Session owner identifier." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "cookies" ], "properties": { "cookies": { "type": "array", "maxItems": 500, "items": { "type": "object", "required": [ "name", "value", "domain" ], "properties": { "name": { "type": "string" }, "value": { "type": "string" }, "domain": { "type": "string" }, "path": { "type": "string" }, "expires": { "type": "number" }, "httpOnly": { "type": "boolean" }, "secure": { "type": "boolean" }, "sameSite": { "type": "string", "enum": [ "Strict", "Lax", "None" ] } } } } } } } } }, "responses": { "200": { "description": "Cookies imported.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "userId": { "type": "string" }, "count": { "type": "integer" } } } } } }, "400": { "description": "Invalid cookie data.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/health": { "get": { "tags": [ "System" ], "summary": "Health check", "description": "Detailed health with tab/session counts and failure tracking.", "responses": { "200": { "description": "Healthy.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "engine": { "type": "string" }, "browserConnected": { "type": "boolean" }, "browserRunning": { "type": "boolean" }, "activeTabs": { "type": "integer" }, "activeSessions": { "type": "integer" }, "consecutiveFailures": { "type": "integer" } } } } } }, "503": { "description": "Unhealthy or recovering.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "recovering": { "type": "boolean" } } } } } } } } }, "/metrics": { "get": { "tags": [ "System" ], "summary": "Prometheus metrics", "description": "Returns Prometheus text exposition format. Requires PROMETHEUS_ENABLED=1.", "responses": { "200": { "description": "Prometheus metrics.", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Metrics disabled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/pressure/cleanup": { "post": { "tags": [ "System" ], "summary": "Proactive memory-pressure cleanup", "description": "Closes tabs observed idle across multiple checks while preserving tabs\nwith active/queued operations. Never returns URLs, titles, cookies,\npage text, or user IDs. Defaults to dry-run mode.\n", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "dryRun": { "type": "boolean", "default": true, "description": "When true, returns candidates without closing them." }, "minIdleMs": { "type": "number", "default": 600000, "description": "Minimum idle time (ms) before a tab is eligible." }, "maxTabsToClose": { "type": "number", "default": 4, "description": "Maximum tabs to close per invocation." }, "minTabsPerSession": { "type": "number", "default": 1, "description": "Preserve at least this many tabs per session." }, "closeEmptySessions": { "type": "boolean", "default": true, "description": "Close sessions left with zero tabs after cleanup." } } } } } }, "responses": { "200": { "description": "Cleanup result with before/after counts and hashed metadata.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "dryRun": { "type": "boolean" }, "before": { "type": "object", "properties": { "sessions": { "type": "integer" }, "tabs": { "type": "integer" } } }, "after": { "type": "object", "properties": { "sessions": { "type": "integer" }, "tabs": { "type": "integer" } } }, "candidates": { "type": "integer" }, "closed": { "type": "array", "items": { "type": "object" } }, "preserved": { "type": "object" } } } } } } } } }, "/tabs": { "post": { "tags": [ "Tabs" ], "summary": "Create a new tab", "description": "Creates a tab in the given session. Optionally navigates to an initial URL.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "sessionKey" ], "properties": { "userId": { "type": "string", "description": "Session owner." }, "sessionKey": { "type": "string", "description": "Tab group identifier." }, "listItemId": { "type": "string", "description": "Legacy alias for sessionKey." }, "url": { "type": "string", "description": "Optional initial URL." }, "trace": { "type": "boolean", "description": "Enable Playwright tracing for this session (screenshots, DOM snapshots, network). Must be set on first tab creation; cannot be added to an existing session." } } } } } }, "responses": { "200": { "description": "Tab created.", "content": { "application/json": { "schema": { "type": "object", "properties": { "tabId": { "type": "string" }, "url": { "type": "string" } } } } } }, "400": { "description": "Missing required fields.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Cannot enable tracing on an existing session.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Tab limit reached.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "get": { "tags": [ "Tabs" ], "summary": "List open tabs", "description": "Returns all tabs for a given userId.", "parameters": [ { "name": "userId", "in": "query", "schema": { "type": "string" }, "description": "Filter by session owner." } ], "responses": { "200": { "description": "Tab list.", "content": { "application/json": { "schema": { "type": "object", "properties": { "running": { "type": "boolean" }, "tabs": { "type": "array", "items": { "type": "object", "properties": { "tabId": { "type": "string" }, "targetId": { "type": "string" }, "url": { "type": "string" }, "title": { "type": "string" }, "listItemId": { "type": "string" } } } } } } } } } } } }, "/tabs/{tabId}/navigate": { "post": { "tags": [ "Navigation" ], "summary": "Navigate a tab to a URL or macro", "description": "Navigate to a URL or expand a search macro. Auto-creates tab if not found.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" }, "url": { "type": "string" }, "macro": { "type": "string", "description": "Search macro (e.g. @google_search)." }, "query": { "type": "string", "description": "Search query for macro." }, "sessionKey": { "type": "string" }, "listItemId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Navigation result with snapshot.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/snapshot": { "get": { "tags": [ "Content" ], "summary": "Accessibility snapshot", "description": "Returns accessibility tree with element refs. Supports pagination via offset.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } }, { "name": "format", "in": "query", "schema": { "type": "string", "enum": [ "text", "json" ], "default": "text" } }, { "name": "offset", "in": "query", "schema": { "type": "integer" }, "description": "Character offset for paginated retrieval." }, { "name": "includeScreenshot", "in": "query", "schema": { "type": "string", "enum": [ "true", "false" ] } } ], "responses": { "200": { "description": "Snapshot.", "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string" }, "snapshot": { "type": "string" }, "refsCount": { "type": "integer" }, "truncated": { "type": "boolean" }, "totalChars": { "type": "integer" }, "hasMore": { "type": "boolean" }, "nextOffset": { "type": "integer" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/wait": { "post": { "tags": [ "Interaction" ], "summary": "Wait for a selector or timeout", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" }, "selector": { "type": "string" }, "timeout": { "type": "integer", "description": "Max wait in ms." } } } } } }, "responses": { "200": { "description": "Wait completed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/click": { "post": { "tags": [ "Interaction" ], "summary": "Click an element", "description": "Click by element ref, CSS selector, or coordinates.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" }, "ref": { "type": "string", "description": "Element ref ID (e.g. \"e3\")." }, "selector": { "type": "string", "description": "CSS selector fallback." }, "doubleClick": { "type": "boolean" }, "coordinates": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } } } } } } } }, "responses": { "200": { "description": "Click result with optional post-action snapshot.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Page changed during the click; caller should take a fresh snapshot and retry with current refs.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/upload": { "post": { "tags": [ "Interaction" ], "summary": "Attach a file to an upload control", "description": "Attaches files from the configured upload directory without going through the native OS file dialog. Set CAMOFOX_UPLOADS_DIR to a directory that contains the files (default: ~/.camofox/uploads). Two strategies are tried in order: (1) if an is already present, call Playwright setInputFiles on it directly (works for hidden inputs); (2) otherwise arm a filechooser listener, activate the trigger element (ref or selector) via keyboard (focus + Enter) then a forced click as fallback, and call setFiles on the resulting chooser. Each path must be an absolute path that resolves inside the configured upload directory.\n", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "path" ], "properties": { "userId": { "type": "string" }, "path": { "description": "Absolute path, or array of paths, that resolves within CAMOFOX_UPLOADS_DIR.", "oneOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ] }, "ref": { "type": "string", "description": "Trigger element ref (e.g. e36). Optional when an input[type=file] already exists." }, "selector": { "type": "string", "description": "Trigger element CSS/Playwright selector. Optional when an input[type=file] already exists." }, "timeout": { "type": "integer", "default": 12000, "description": "Overall budget in ms to wait for an upload UI (in-app panel input or native file chooser) to appear after the trigger is activated. Ignored values (non-numeric or <= 0) fall back to the default." } } } } } }, "responses": { "200": { "description": "File(s) attached." }, "400": { "description": "Bad request (missing path/userId; non-regular file; or a path that is missing or outside the configured upload directory)." }, "404": { "description": "Tab not found." } } } }, "/tabs/{tabId}/type": { "post": { "tags": [ "Interaction" ], "summary": "Type text into an element", "description": "Types text into a focused element or a specific ref/selector.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "text" ], "properties": { "userId": { "type": "string" }, "ref": { "type": "string" }, "selector": { "type": "string" }, "text": { "type": "string" }, "clear": { "type": "boolean", "description": "Clear field before typing." }, "submit": { "type": "boolean", "description": "Press Enter after typing." } } } } } }, "responses": { "200": { "description": "Type result.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Page changed or target became invalid; caller should take a fresh snapshot and retry.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/press": { "post": { "tags": [ "Interaction" ], "summary": "Press a keyboard key", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "key" ], "properties": { "userId": { "type": "string" }, "key": { "type": "string", "description": "Key name (e.g. \"Enter\", \"Escape\", \"Tab\")." } } } } } }, "responses": { "200": { "description": "Key pressed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/scroll": { "post": { "tags": [ "Interaction" ], "summary": "Scroll the page", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" }, "direction": { "type": "string", "description": "\"up\" or \"down\" (default \"down\")." }, "amount": { "type": "integer", "description": "Pixels to scroll." } } } } } }, "responses": { "200": { "description": "Scroll result.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/viewport": { "post": { "tags": [ "Interaction" ], "summary": "Set the page viewport size", "description": "Physically resizes the page via Playwright's `page.setViewportSize`, triggering a real layout reflow. Use for responsive testing — `window.resizeTo()` is a no-op on non-popup windows.\n", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "width", "height" ], "properties": { "userId": { "type": "string" }, "width": { "type": "integer", "minimum": 100, "maximum": 4000 }, "height": { "type": "integer", "minimum": 100, "maximum": 4000 } } } } } }, "responses": { "200": { "description": "Viewport set.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "width": { "type": "integer" }, "height": { "type": "integer" } } } } } }, "400": { "description": "Width or height missing or out of range." }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/back": { "post": { "tags": [ "Navigation" ], "summary": "Go back", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Navigated back.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "url": { "type": "string" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/forward": { "post": { "tags": [ "Navigation" ], "summary": "Go forward", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Navigated forward.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "url": { "type": "string" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/refresh": { "post": { "tags": [ "Navigation" ], "summary": "Refresh page", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId" ], "properties": { "userId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Page refreshed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "url": { "type": "string" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/links": { "get": { "tags": [ "Content" ], "summary": "Extract page links", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Links extracted.", "content": { "application/json": { "schema": { "type": "object", "properties": { "links": { "type": "array", "items": { "type": "object", "properties": { "text": { "type": "string" }, "href": { "type": "string" }, "ref": { "type": "string" } } } } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/downloads": { "get": { "tags": [ "Content" ], "summary": "List tab downloads", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Downloads list.", "content": { "application/json": { "schema": { "type": "object", "properties": { "downloads": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string" }, "url": { "type": "string" }, "state": { "type": "string" } } } } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/images": { "get": { "tags": [ "Content" ], "summary": "Extract page images", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Images extracted.", "content": { "application/json": { "schema": { "type": "object", "properties": { "images": { "type": "array", "items": { "type": "object", "properties": { "src": { "type": "string" }, "alt": { "type": "string" }, "width": { "type": "integer" }, "height": { "type": "integer" } } } } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/screenshot": { "get": { "tags": [ "Content" ], "summary": "Take a screenshot", "description": "Returns a base64-encoded PNG screenshot.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Screenshot.", "content": { "application/json": { "schema": { "type": "object", "properties": { "screenshot": { "type": "object", "properties": { "data": { "type": "string" }, "mimeType": { "type": "string" } } } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/stats": { "get": { "tags": [ "Tabs" ], "summary": "Tab statistics", "description": "Returns tab metadata including URL, tool call count, visited URLs, download/failure counts.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Tab stats.", "content": { "application/json": { "schema": { "type": "object", "properties": { "tabId": { "type": "string" }, "url": { "type": "string" }, "toolCalls": { "type": "integer" }, "visitedUrls": { "type": "array", "items": { "type": "string" } }, "downloadCount": { "type": "integer" }, "consecutiveFailures": { "type": "integer" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/evaluate": { "post": { "tags": [ "Interaction" ], "summary": "Evaluate JavaScript in tab", "description": "Runs arbitrary JS in the page context and returns the result.", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "expression" ], "properties": { "userId": { "type": "string" }, "expression": { "type": "string", "description": "JavaScript expression to evaluate." } } } } } }, "responses": { "200": { "description": "Evaluation result.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "result": {} } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Page navigated while evaluating; caller should retry once the page settles.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Browser session expired; caller should retry to get a fresh session.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}/extract": { "post": { "tags": [ "Content" ], "summary": "Structured data extraction via JSON Schema", "description": "Extracts structured data from the current page using a JSON Schema whose properties\ncarry `x-ref` hints pointing at snapshot element refs (e.g. `e1`, `e2`). \nCall `GET /tabs/{tabId}/snapshot` first to populate the ref table.\n", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "schema" ], "properties": { "userId": { "type": "string" }, "schema": { "type": "object", "description": "JSON Schema with `type: \"object\"` and a `properties` map. \nEach property may include `x-ref` (a snapshot element ref) and an optional\n`type` (`string`, `number`, `integer`, `boolean`).\n", "required": [ "type", "properties" ], "properties": { "type": { "type": "string", "enum": [ "object" ] }, "properties": { "type": "object", "additionalProperties": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "object", "null" ] }, "x-ref": { "type": "string", "description": "Snapshot element ref (e.g. `e1`)." } } } }, "required": { "type": "array", "items": { "type": "string" }, "description": "Property names that must resolve to a non-null value." } } } } } } } }, "responses": { "200": { "description": "Extraction succeeded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "data": { "type": "object", "description": "Extracted key-value pairs matching the input schema." } } } } } }, "400": { "description": "Missing userId, missing schema, or invalid schema.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "No refs available -- call snapshot first.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" }, "snapshot": { "type": "string", "nullable": true } } } } } }, "422": { "description": "Extraction failed (e.g. required ref not found).", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "error": { "type": "string" }, "snapshot": { "type": "string", "nullable": true } } } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/{tabId}": { "delete": { "tags": [ "Tabs" ], "summary": "Close a tab", "parameters": [ { "name": "tabId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Tab closed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" } } } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tabs/group/{listItemId}": { "delete": { "tags": [ "Tabs" ], "summary": "Close all tabs in a group", "parameters": [ { "name": "listItemId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Group closed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "closed": { "type": "integer" } } } } } }, "404": { "description": "Session not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/sessions/{userId}/traces": { "get": { "tags": [ "Sessions" ], "summary": "List trace files", "description": "Returns all Playwright trace zip files for the given user session, sorted newest first.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Session owner identifier." } ], "responses": { "200": { "description": "Trace list.", "content": { "application/json": { "schema": { "type": "object", "properties": { "traces": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string" }, "sizeBytes": { "type": "integer" }, "createdAt": { "type": "number" }, "modifiedAt": { "type": "number" } } } } } } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/sessions/{userId}/traces/{filename}": { "get": { "tags": [ "Sessions" ], "summary": "Download a trace file", "description": "Streams a Playwright trace zip for viewing in trace.playwright.dev.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Session owner identifier." }, { "name": "filename", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Trace zip filename." } ], "responses": { "200": { "description": "Trace zip stream.", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Invalid filename.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Trace not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": [ "Sessions" ], "summary": "Delete a trace file", "description": "Removes a specific Playwright trace zip from the server.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Session owner identifier." }, { "name": "filename", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Trace zip filename." } ], "responses": { "200": { "description": "Trace deleted.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" } } } } } }, "400": { "description": "Invalid filename.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Trace not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/sessions/{userId}": { "delete": { "tags": [ "Sessions" ], "summary": "Destroy a user session", "description": "Closes all tabs and cleans up state for the given userId.", "parameters": [ { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Session destroyed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "closed": { "type": "integer" } } } } } }, "404": { "description": "Session not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/": { "get": { "tags": [ "System" ], "summary": "Server status", "description": "Returns basic server liveness and browser state.", "responses": { "200": { "description": "Server status.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "enabled": { "type": "boolean" }, "running": { "type": "boolean" }, "engine": { "type": "string" }, "browserConnected": { "type": "boolean" }, "browserRunning": { "type": "boolean" } } } } } } } } }, "/tabs/open": { "post": { "tags": [ "Legacy" ], "summary": "Open tab (OpenClaw format)", "deprecated": true, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "url" ], "properties": { "userId": { "type": "string" }, "url": { "type": "string" }, "listItemId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Tab opened.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/start": { "post": { "tags": [ "Browser" ], "summary": "Start browser", "description": "Ensures the browser process is running. Idempotent.", "responses": { "200": { "description": "Browser started.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "profile": { "type": "string" } } } } } }, "500": { "description": "Launch failed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/stop": { "post": { "tags": [ "Browser" ], "summary": "Stop browser", "description": "Stops the browser and closes all sessions. Requires x-admin-key header.", "security": [ { "BearerAuth": [] } ], "responses": { "200": { "description": "Browser stopped.", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "stopped": { "type": "boolean" }, "profile": { "type": "string" } } } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/navigate": { "post": { "tags": [ "Legacy" ], "summary": "Navigate (OpenClaw format)", "description": "Navigate with targetId in body instead of path param.", "deprecated": true, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "url" ], "properties": { "userId": { "type": "string" }, "targetId": { "type": "string" }, "url": { "type": "string" } } } } } }, "responses": { "200": { "description": "Navigation result.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/snapshot": { "get": { "tags": [ "Legacy" ], "summary": "Snapshot (OpenClaw format)", "description": "Snapshot with targetId/userId as query params.", "deprecated": true, "parameters": [ { "name": "targetId", "in": "query", "required": true, "schema": { "type": "string" } }, { "name": "userId", "in": "query", "required": true, "schema": { "type": "string" } }, { "name": "format", "in": "query", "schema": { "type": "string" } }, { "name": "offset", "in": "query", "schema": { "type": "integer" } }, { "name": "includeScreenshot", "in": "query", "schema": { "type": "string", "enum": [ "true", "false" ] } } ], "responses": { "200": { "description": "Snapshot.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/act": { "post": { "tags": [ "Legacy" ], "summary": "Combined action (OpenClaw format)", "description": "Routes to click/type/scroll/press/etc based on \"kind\" parameter.", "deprecated": true, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "userId", "kind" ], "properties": { "userId": { "type": "string" }, "kind": { "type": "string", "description": "Action kind: click, type, scroll, press, key, select_option, drag, hover, screenshot, wait, back, forward." }, "targetId": { "type": "string" }, "ref": { "type": "string" }, "selector": { "type": "string" }, "text": { "type": "string" }, "key": { "type": "string" }, "direction": { "type": "string" }, "url": { "type": "string" } } } } } }, "responses": { "200": { "description": "Action result.", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Tab not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } } } }