PPradeep Elankumaranrelease: prepare v1.18.1 patch
72572d24创建于 23 天前历史提交
{
  "openapi": "3.0.3",
  "info": {
    "title": "camofox-browser",
    "version": "1.18.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"
                    },
                    "httpStatus": {
                      "type": "integer",
                      "nullable": true,
                      "description": "HTTP status of the optional initial document navigation."
                    },
                    "navigationOk": {
                      "type": "boolean",
                      "description": "False when the optional initial document navigation returned HTTP 400 or higher."
                    }
                  }
                }
              }
            }
          },
          "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. Destination HTTP status is reported even when a rendered error page is available.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "tabId": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "httpStatus": {
                      "type": "integer",
                      "nullable": true,
                      "description": "HTTP status of the final document navigation when available."
                    },
                    "navigationOk": {
                      "type": "boolean",
                      "description": "False when the final document returned an HTTP status of 400 or greater."
                    }
                  }
                }
              }
            }
          },
          "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"
                    },
                    "structure": {
                      "type": "object",
                      "description": "Optional bounded read-only DOM summary of forms and tables. The snapshot field remains unchanged."
                    },
                    "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}/select": {
      "post": {
        "tags": [
          "Interaction"
        ],
        "summary": "Select a native form option",
        "parameters": [
          {
            "name": "tabId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId",
                  "option"
                ],
                "properties": {
                  "userId": {
                    "type": "string"
                  },
                  "ref": {
                    "type": "string"
                  },
                  "selector": {
                    "type": "string"
                  },
                  "option": {
                    "type": "string",
                    "description": "Visible option label or HTML value."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Option selected.",
            "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}/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}/fetch-current-resource": {
      "post": {
        "tags": [
          "Content"
        ],
        "summary": "Save the current tab's PDF as a download artifact",
        "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": "Saved PDF download artifact."
          },
          "404": {
            "description": "Tab not found."
          },
          "415": {
            "description": "Current resource is not a PDF."
          }
        }
      }
    },
    "/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"
                }
              }
            }
          }
        }
      }
    }
  }
}