openapi: 3.0.1
info:
  title: AgentBrowser
  description: Drive a real, hosted browser — open pages, read them, click/type, extract data.
  version: "0.1.0"
servers:
  - url: https://app.getagentbrowser.com
paths:
  /api/sessions:
    post:
      operationId: createSession
      summary: Open a hosted browser session on a live render node.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  description: "Optional public HTTP(S) URL to open immediately (default about:blank). Exact about:blank is allowed; credentials, loopback, private, link-local, metadata, mixed public/private DNS answers, and every other scheme are rejected."
                profile:
                  type: string
                  enum: [desktop, mobile]
                  description: "mobile emulates an iPhone-class device (viewport, UA, touch)."
                record:
                  type: boolean
                  description: "Capture video + console/network/DOM events, downloadable as a tar.gz. Not supported when cdp is true."
                dom:
                  type: boolean
                  description: "Also record an rrweb-style DOM track. Not supported when cdp is true."
                no_video:
                  type: boolean
                  description: "Skip the mp4 (events only). Not supported when cdp is true."
                cdp:
                  type: boolean
                  description: "Raw-CDP session: allocate a dedicated, isolated browser you drive over the Chrome DevTools Protocol (Playwright/Puppeteer connectOverCDP). Node-enforced public-only egress remains active. The response includes cdp_url; the act verb surface does not apply, and record/dom/no_video are rejected."
                region:
                  type: string
                  description: "Preferred render region (best-effort). The plane routes to a node in this region when one has capacity, else the least-loaded node anywhere."
      responses:
        "200":
          description: Session created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id: { type: string }
                  cdp_url:
                    type: string
                    description: "Present when cdp:true — the preferred complete wss:// URL carrying a short-lived, session-scoped ticket; hand it to connectOverCDP unchanged. Alternatively connect to /api/sessions/{id}/cdp and send the workspace gbk_ API key in an Authorization: Bearer header. Never put a reusable API key in a query string."
        "400": { description: "Invalid options, including caller proxy/bypass settings or hosted recorder options combined with cdp:true." }
        "503": { description: No render node available. }
  /api/sessions/{id}/act:
    post:
      operationId: act
      summary: Drive the session with a verb.
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [verb]
              properties:
                verb:
                  type: string
                  description: >-
                    The full canonical verb set, kept in sync with
                    cmd/gb-noded's action switch by this repo's
                    internal/conformance conformance check (P2-210) — a `go
                    test` failure blocks any release that lets this list drift
                    from what the node/MCP/SDK surfaces actually support.
                  enum: [navigate, snapshot, click, type, select, check, hover, press, back, forward, reload, scroll, read_page, extract, extract_all, evaluate, wait_for, screenshot, pdf, get_cookies, set_cookies, click_at, move_to, drag, mark, login, set_file_input, wait_for_download, get_download, list_downloads, cancel_download, wait_for_dialog, handle_dialog, get_dialog, list_tabs, current_tab, switch_tab, new_tab, close_tab, wait_for_popup, wait_for_response, get_response_body, block_requests, set_header_overrides, unblock_requests, request_human_takeover, resume_from_takeover, export_storage_state, import_storage_state]
                url: { type: string, description: "for navigate, new_tab" }
                ref: { type: string, description: "an [e#] ref from snapshot (click/type)" }
                selector: { type: string, description: "CSS selector (click/type/extract)" }
                fields:
                  type: object
                  additionalProperties: { type: string }
                  description: "Object mapping result names to CSS selectors for extract_all; response values use the same names and are null when no element matches."
                text: { type: string, description: "text to type" }
                expression: { type: string, description: "JS to evaluate" }
                predicate: { type: string, description: "JS predicate for wait_for" }
                secret: { type: string, description: "vault secret name (login)" }
                cookies:
                  type: array
                  items: { type: object, additionalProperties: true }
                  description: "Chrome DevTools Protocol CookieParam objects passed to Network.setCookies for set_cookies."
                x: { type: number, description: "viewport x px (click_at/move_to/drag)" }
                y: { type: number, description: "viewport y px (click_at/move_to/drag)" }
                to_x: { type: number, description: "drag end x px" }
                to_y: { type: number, description: "drag end y px" }
                value: { type: string, description: "option to choose (select)" }
                checked: { type: boolean, description: "desired state (check)" }
                key: { type: string, description: "key to press, e.g. Enter (press)" }
                dx: { type: integer, description: "horizontal scroll px (scroll)" }
                dy: { type: integer, description: "vertical scroll px (scroll)" }
                file_data_base64: { type: string, description: "base64 file bytes for set_file_input (selector/ref pick the input)" }
                download_guid: { type: string, description: "for wait_for_download/get_download/cancel_download; empty waits for the next download" }
                timeout_ms: { type: integer, description: "for wait_for_download/wait_for_dialog/wait_for_popup/wait_for_response/cancel_download" }
                accept: { type: boolean, description: "accept (true) or dismiss (false) the pending dialog (handle_dialog)" }
                prompt_text: { type: string, description: "text to answer a JS prompt() with (handle_dialog)" }
                tab_id: { type: string, description: "for switch_tab/close_tab" }
                tab_index: { type: integer, description: "0-based tab index, alternative to tab_id (switch_tab)" }
                url_pattern: { type: string, description: "URL substring match (wait_for_response)" }
                method: { type: string, description: "HTTP method filter, e.g. POST (wait_for_response)" }
                request_id: { type: string, description: "network request id from wait_for_response (get_response_body)" }
                patterns:
                  type: array
                  items: { type: string }
                  description: "URL substrings to block (block_requests) — matches either patterns or resource_types."
                resource_types:
                  type: array
                  items: { type: string }
                  description: "CDP Network.ResourceType values to block, e.g. image, stylesheet, font (block_requests)."
                overrides:
                  type: array
                  description: >-
                    Replaces the session's full request-header-override rule list
                    (set_header_overrides). Reliable for ordinary headers; Chrome
                    recomputes a few browser-managed ones (notably Referer) after
                    request interception regardless of what this call sends, so a
                    remove rule on those is not guaranteed to reach the real
                    outgoing request — a verified Chrome/CDP limitation, not a bug
                    in this API.
                  items:
                    type: object
                    properties:
                      url_pattern: { type: string, description: "substring match, empty matches every request" }
                      set:
                        type: object
                        additionalProperties: { type: string }
                        description: "headers to add/replace"
                      remove:
                        type: array
                        items: { type: string }
                        description: "headers to delete"
                reason: { type: string, description: "why human takeover is needed (request_human_takeover)" }
                storage_state:
                  type: object
                  additionalProperties: true
                  description: "cookies + per-origin localStorage previously returned by export_storage_state (import_storage_state)."
      responses:
        "200":
          description: Result of the verb (shape depends on the verb).
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  outline: { type: string, description: "for snapshot" }
                  text: { type: string, description: "for read_page/extract" }
                  value: { description: "for evaluate" }
                  png_base64: { type: string, description: "for screenshot" }
                  pdf_base64: { type: string, description: "for pdf" }
        "404": { description: Unknown session (or not yours). }
  /api/sessions/{id}:
    delete:
      operationId: closeSession
      summary: Close the session (billed for wall-time held).
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Closed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  billed_seconds: { type: number }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
    # mcpOAuth documents AgentBrowser's separate MCP (Model Context
    # Protocol) surface — cmd/gb-mcp's Streamable HTTP transport, not the
    # REST /api/sessions paths this document otherwise describes. gb-server
    # is its own minimal OIDC-style issuer (see internal/mcpjwt,
    # cmd/gb-server's mcp_oauth.go): it mints short-lived ES256 JWTs scoped
    # to browser:read/browser:write/browser:admin from an existing signed-in
    # session or workspace API key, and publishes the verification key at
    # GET /.well-known/jwks.json. No paths in THIS document use it (it is
    # declared here only so a client discovering this manifest can also
    # discover the MCP auth flow); see /.well-known/oauth-protected-resource
    # on the MCP endpoint itself for RFC 9728 protected-resource metadata.
    mcpOAuth:
      type: oauth2
      description: >-
        Bearer tokens for AgentBrowser's MCP server (a separate surface from
        the REST API above). Self-issued, short-lived ES256 JWTs; mint one
        with an existing session cookie or workspace API key via the token
        endpoint below, then verify/introspect against
        https://app.getagentbrowser.com/.well-known/jwks.json.
      flows:
        clientCredentials:
          tokenUrl: https://app.getagentbrowser.com/api/mcp/token
          scopes:
            browser:read: Read-only browser actions (snapshot, extract, screenshot, read_page, ...)
            browser:write: Mutating browser actions (navigate, click, type, select, ...)
            browser:admin: Session lifecycle and credential injection (new_session, login, close_session)
security:
  - bearerAuth: []
