{"owner":"jo-inc","repo":"camofox-browser","hasSpec":true,"specFile":"openapi.json","branch":"HEAD","format":"json","version":"3.0.3","title":"camofox-browser","description":"Anti-detection browser automation server for AI agents. Accessibility snapshots, element refs, session isolation, cookie import, proxy rotation, and structured logs.","pathsCount":36,"endpoints":[{"method":"POST","path":"/sessions/{userId}/cookies","summary":"Import cookies into a user session"},{"method":"GET","path":"/health","summary":"Health check"},{"method":"GET","path":"/metrics","summary":"Prometheus metrics"},{"method":"POST","path":"/pressure/cleanup","summary":"Proactive memory-pressure cleanup"},{"method":"POST","path":"/tabs","summary":"Create a new tab"},{"method":"GET","path":"/tabs","summary":"List open tabs"},{"method":"POST","path":"/tabs/{tabId}/navigate","summary":"Navigate a tab to a URL or macro"},{"method":"GET","path":"/tabs/{tabId}/snapshot","summary":"Accessibility snapshot"},{"method":"POST","path":"/tabs/{tabId}/wait","summary":"Wait for a selector or timeout"},{"method":"POST","path":"/tabs/{tabId}/click","summary":"Click an element"},{"method":"POST","path":"/tabs/{tabId}/upload","summary":"Attach a file to an upload control"},{"method":"POST","path":"/tabs/{tabId}/type","summary":"Type text into an element"},{"method":"POST","path":"/tabs/{tabId}/press","summary":"Press a keyboard key"},{"method":"POST","path":"/tabs/{tabId}/scroll","summary":"Scroll the page"},{"method":"POST","path":"/tabs/{tabId}/viewport","summary":"Set the page viewport size"},{"method":"POST","path":"/tabs/{tabId}/back","summary":"Go back"},{"method":"POST","path":"/tabs/{tabId}/forward","summary":"Go forward"},{"method":"POST","path":"/tabs/{tabId}/refresh","summary":"Refresh page"},{"method":"GET","path":"/tabs/{tabId}/links","summary":"Extract page links"},{"method":"GET","path":"/tabs/{tabId}/downloads","summary":"List tab downloads"},{"method":"GET","path":"/tabs/{tabId}/images","summary":"Extract page images"},{"method":"GET","path":"/tabs/{tabId}/screenshot","summary":"Take a screenshot"},{"method":"GET","path":"/tabs/{tabId}/stats","summary":"Tab statistics"},{"method":"POST","path":"/tabs/{tabId}/evaluate","summary":"Evaluate JavaScript in tab"},{"method":"POST","path":"/tabs/{tabId}/extract","summary":"Structured data extraction via JSON Schema"},{"method":"DELETE","path":"/tabs/{tabId}","summary":"Close a tab"},{"method":"DELETE","path":"/tabs/group/{listItemId}","summary":"Close all tabs in a group"},{"method":"GET","path":"/sessions/{userId}/traces","summary":"List trace files"},{"method":"GET","path":"/sessions/{userId}/traces/{filename}","summary":"Download a trace file"},{"method":"DELETE","path":"/sessions/{userId}/traces/{filename}","summary":"Delete a trace file"},{"method":"DELETE","path":"/sessions/{userId}","summary":"Destroy a user session"},{"method":"GET","path":"/","summary":"Server status"},{"method":"POST","path":"/tabs/open","summary":"Open tab (OpenClaw format)"},{"method":"POST","path":"/start","summary":"Start browser"},{"method":"POST","path":"/stop","summary":"Stop browser"},{"method":"POST","path":"/navigate","summary":"Navigate (OpenClaw format)"},{"method":"GET","path":"/snapshot","summary":"Snapshot (OpenClaw format)"},{"method":"POST","path":"/act","summary":"Combined action (OpenClaw format)"}],"spec":{"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 <input type=\"file\"> 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"}}}}}}}}}}