openapi: 3.1.0
info:
  title: SpiderFly Public Web Data API
  version: 1.0.0
  summary: Public-only OpenAPI source of truth for SpiderFly v1 Web Data APIs.
  description: >
    Public-only OpenAPI draft and source of truth for confirmed SpiderFly /v1
    routes. This hand-written or semi-hand-written document follows the Phase 0
    route boundary decisions in docs/api-route-boundary-inventory-2026-06-21.md
    and the unique Web Data API contract in
    docs/public-v1-web-data-api-contract-2026-06-21.md. It intentionally
    contains only /v1/* paths and must not be generated from the full FastAPI
    application schema. Browser session endpoints expose a Browserless-style
    lifecycle surface, but not the full Browserless API protocol.
servers:
  - url: /v1
    description: Public v1 API base path.
tags:
  - name: Fetch
  - name: Extract
  - name: Browser Scrape
  - name: Browser Inventory
  - name: Crawl
  - name: Runs
  - name: YouTube
  - name: Reddit
  - name: Google Maps
  - name: Google Trends
paths:
  /v1/fetch:
    post:
      tags:
        - Fetch
      operationId: fetchPage
      summary: Fetch one URL.
      description: Fetches one URL and returns a public page result.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FetchRequest"
      responses:
        "200":
          description: Fetch completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageRunResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "408":
          $ref: "#/components/responses/Timeout"
        "409":
          $ref: "#/components/responses/IdempotencyConflict"
        "429":
          $ref: "#/components/responses/QuotaExceeded"
        "502":
          $ref: "#/components/responses/FetchFailed"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/extract:
    post:
      tags:
        - Extract
      operationId: extractStructuredData
      summary: Extract structured data from supplied HTML.
      description: >
        Runs allowlisted Crawl4AI structured extraction against caller-supplied HTML.
        This endpoint does not fetch the URL, open a browser, persist artifacts, or create a run.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExtractRequest"
      responses:
        "200":
          description: Structured extraction completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExtractResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/scrape:
    post:
      tags:
        - Browser Scrape
      operationId: browserScrapePage
      summary: Browser-scrape one URL.
      description: >
        Runs one product-safe browser-backed scrape for one URL. Optional
        structured extraction runs over the rendered HTML through the safe
        Crawl4AI extraction contract.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrowserScrapeRequest"
      responses:
        "200":
          description: Browser scrape completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageRunResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "408":
          $ref: "#/components/responses/Timeout"
        "409":
          $ref: "#/components/responses/IdempotencyConflict"
        "429":
          $ref: "#/components/responses/QuotaExceeded"
        "502":
          $ref: "#/components/responses/RenderFailed"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/sessions:
    get:
      tags:
        - Browser Inventory
      operationId: listBrowserSessions
      summary: List active browser sessions.
      description: Lists public-safe active browser session metadata without CDP or live-control URLs.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Browser sessions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserSessionsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    post:
      tags:
        - Browser Inventory
      operationId: createBrowserSession
      summary: Create a browser session.
      description: Creates a managed browser session and returns public-safe session metadata plus a connect endpoint.
      security:
        - BearerAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrowserSessionCreateRequest"
      responses:
        "201":
          description: Browser session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserSessionCreateResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/sessions/{session_id}:
    get:
      tags:
        - Browser Inventory
      operationId: getBrowserSession
      summary: Get a browser session.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: Browser session.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserSessionResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/SessionNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    delete:
      tags:
        - Browser Inventory
      operationId: stopBrowserSession
      summary: Stop a browser session.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: Browser session stop result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserSessionStopResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/SessionNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/sessions/{session_id}/connect:
    get:
      tags:
        - Browser Inventory
      operationId: connectBrowserSession
      summary: Get a browser session websocket endpoint.
      description: Returns the authenticated websocket endpoint for an active session.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: Browser session websocket endpoint.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserSessionConnectResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/SessionNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/profile-pools:
    get:
      tags:
        - Browser Inventory
      operationId: listBrowserProfilePools
      summary: List browser profile pools.
      description: Lists current public-safe browser profile pool inventory without provider group IDs or raw profile payloads. Profile pools are pool inventory, not persisted browser profile metadata.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Browser profile pools.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserProfilePoolsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/profiles:
    get:
      tags:
        - Browser Inventory
      operationId: listBrowserProfiles
      summary: List managed browser profiles.
      description: Lists public-safe managed browser profile metadata. Use /v1/browser/profile-pools for current provider pool inventory.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Managed browser profiles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserProfilesResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    post:
      tags:
        - Browser Inventory
      operationId: createBrowserProfile
      summary: Create a managed browser profile resource.
      description: Creates public-safe profile metadata; it does not expose provider raw profile payloads.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrowserProfileCreateRequest"
      responses:
        "201":
          description: Browser profile created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserProfileResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/browser/profiles/{profile_id}:
    get:
      tags:
        - Browser Inventory
      operationId: getBrowserProfile
      summary: Get a managed browser profile resource.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/ProfileId"
      responses:
        "200":
          description: Browser profile.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserProfileResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/ProfileNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    patch:
      tags:
        - Browser Inventory
      operationId: updateBrowserProfile
      summary: Update a managed browser profile resource.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/ProfileId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrowserProfileUpdateRequest"
      responses:
        "200":
          description: Browser profile updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserProfileResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/ProfileNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    delete:
      tags:
        - Browser Inventory
      operationId: deleteBrowserProfile
      summary: Delete a managed browser profile resource.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/ProfileId"
      responses:
        "200":
          description: Browser profile deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrowserProfileDeleteResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/ProfileNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/crawl:
    post:
      tags:
        - Crawl
      operationId: createCrawl
      summary: Create a crawl.
      description: >
        Creates an asynchronous crawl and returns run/job metadata. Optional
        structured extraction runs per crawled page and item-level rows are
        read through /v1/crawl/{crawl_id}/items. The runtime must produce a
        materialized crawl plan before quota reservation; an unavailable
        planning runtime returns 503 without reserving quota or creating a job.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CrawlCreateRequest"
      responses:
        "202":
          description: Crawl accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CrawlCreateResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "409":
          $ref: "#/components/responses/IdempotencyConflict"
        "429":
          $ref: "#/components/responses/QuotaExceeded"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/crawl/{crawl_id}:
    get:
      tags:
        - Crawl
      operationId: getCrawlStatus
      summary: Get crawl status.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/CrawlId"
      responses:
        "200":
          description: Crawl status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CrawlStatusResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/CrawlNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/crawl/{crawl_id}/results:
    get:
      tags:
        - Crawl
      operationId: listCrawlResults
      summary: List crawl results.
      description: Pages through public page results for a crawl.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/CrawlId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - $ref: "#/components/parameters/Status"
      responses:
        "200":
          description: Crawl results page.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CrawlResultsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/CrawlNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/crawl/{crawl_id}/items:
    get:
      tags:
        - Crawl
      operationId: listCrawlItems
      summary: List crawl structured items.
      description: Returns item-level structured extraction rows derived from crawl page results.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/CrawlId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: Crawl structured items page.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CrawlItemsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/CrawlNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/runs:
    get:
      tags:
        - Runs
      operationId: listRuns
      summary: List runs.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - name: type
          in: query
          required: false
          schema:
            $ref: "#/components/schemas/PublicRunType"
        - $ref: "#/components/parameters/Status"
      responses:
        "200":
          description: Runs page.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListRunsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/runs/{run_id}:
    get:
      tags:
        - Runs
      operationId: getRun
      summary: Get run detail.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/RunId"
      responses:
        "200":
          description: Run detail.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/PageRunResponse"
                  - $ref: "#/components/schemas/CrawlRunResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/RunNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/runs/{run_id}/artifacts/{artifact_key}:
    get:
      tags:
        - Runs
      operationId: getRunArtifact
      summary: Download a run artifact.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/RunId"
        - name: artifact_key
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/ArtifactKey"
      responses:
        "200":
          description: Artifact content.
          content:
            text/markdown:
              schema:
                type: string
            text/html:
              schema:
                type: string
            application/json:
              schema:
                type: object
                additionalProperties: true
            image/png:
              schema:
                type: string
                format: binary
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/ArtifactNotFound"
        "410":
          $ref: "#/components/responses/ArtifactExpired"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/monitors:
    get:
      tags:
        - YouTube
      operationId: listYoutubeMonitors
      summary: List YouTube monitors.
      description: Lists YouTube channel monitors configured for public platform monitoring.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: YouTube monitor page.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorListResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    post:
      tags:
        - YouTube
      operationId: createYoutubeMonitor
      summary: Create a YouTube monitor.
      description: >
        Creates a YouTube channel monitor. RSS and yt-dlp polling are peer
        monitoring strategies; `auto` schedules both backends independently.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/YoutubeMonitorCreateRequest"
      responses:
        "201":
          description: YouTube monitor created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/monitors/{monitor_id}:
    get:
      tags:
        - YouTube
      operationId: getYoutubeMonitor
      summary: Get a YouTube monitor.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
      responses:
        "200":
          description: YouTube monitor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    patch:
      tags:
        - YouTube
      operationId: updateYoutubeMonitor
      summary: Update a YouTube monitor.
      description: Updates monitor target, strategy, enabled state, or polling settings.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/YoutubeMonitorPatchRequest"
      responses:
        "200":
          description: Updated YouTube monitor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/monitors/{monitor_id}/check:
    post:
      tags:
        - YouTube
      operationId: checkYoutubeMonitor
      summary: Run a YouTube monitor check now.
      description: >
        Runs the monitor's configured backend strategies immediately. For
        `auto`, RSS and yt-dlp polling both run as peer strategies.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
      responses:
        "200":
          description: YouTube monitor check result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorCheckResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/monitors/{monitor_id}/events:
    get:
      tags:
        - YouTube
      operationId: listYoutubeMonitorEvents
      summary: List YouTube monitor events.
      description: Lists new video, updated video, reschedule, and monitor error events.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: YouTube monitor events.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorEventsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/monitors/{monitor_id}/videos:
    get:
      tags:
        - YouTube
      operationId: listYoutubeMonitorVideos
      summary: List observed YouTube videos.
      description: Lists latest observed video records for a YouTube monitor.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: YouTube monitor videos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMonitorVideosResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/reddit/monitors:
    get:
      tags:
        - Reddit
      operationId: listRedditMonitors
      summary: List Reddit monitors.
      description: Lists Reddit subreddit monitors configured for public platform monitoring.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: Reddit monitor page.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorListResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    post:
      tags:
        - Reddit
      operationId: createRedditMonitor
      summary: Create a Reddit monitor.
      description: >
        Creates a Reddit subreddit monitor backed by the JSON listing fetcher.
        The monitor reuses one logical identity across warmup and polling without
        returning raw cookie values, proxy URLs, or provider profile identifiers.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RedditMonitorCreateRequest"
      responses:
        "201":
          description: Reddit monitor created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/reddit/monitors/{monitor_id}:
    get:
      tags:
        - Reddit
      operationId: getRedditMonitor
      summary: Get a Reddit monitor.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
      responses:
        "200":
          description: Reddit monitor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/RedditMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    patch:
      tags:
        - Reddit
      operationId: updateRedditMonitor
      summary: Update a Reddit monitor.
      description: Updates subreddit target, enabled state, JSON listing sort, or polling settings.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RedditMonitorPatchRequest"
      responses:
        "200":
          description: Updated Reddit monitor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/RedditMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/reddit/monitors/{monitor_id}/check:
    post:
      tags:
        - Reddit
      operationId: checkRedditMonitor
      summary: Run a Reddit monitor check now.
      description: >
        Runs the monitor's JSON listing fetcher immediately and reconciles new
        or updated posts against stored Reddit post records.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
      responses:
        "200":
          description: Reddit monitor check result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorCheckResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/RedditMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/reddit/monitors/{monitor_id}/events:
    get:
      tags:
        - Reddit
      operationId: listRedditMonitorEvents
      summary: List Reddit monitor events.
      description: Lists new post, updated post, and monitor error events.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: Reddit monitor events.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorEventsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/RedditMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/reddit/monitors/{monitor_id}/posts:
    get:
      tags:
        - Reddit
      operationId: listRedditMonitorPosts
      summary: List observed Reddit posts.
      description: Lists latest observed post records for a Reddit monitor.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/MonitorId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: Reddit monitor posts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RedditMonitorPostsResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/RedditMonitorNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/videos/{video_id}/downloads:
    post:
      tags:
        - YouTube
      operationId: createYoutubeDownloadJob
      summary: Create a YouTube download job.
      description: Creates an asynchronous yt-dlp-backed media download job for one YouTube video.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeVideoId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/YoutubeDownloadJobCreateRequest"
      responses:
        "202":
          description: YouTube download job accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMediaJobResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/videos/{video_id}/subtitles:
    get:
      tags:
        - YouTube
      operationId: listYoutubeVideoSubtitles
      summary: List YouTube video subtitles.
      description: Lists subtitle artifacts previously produced by YouTube subtitle jobs.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeVideoId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: YouTube subtitle records.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeVideoSubtitlesResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    post:
      tags:
        - YouTube
      operationId: createYoutubeSubtitleJob
      summary: Create a YouTube subtitle job.
      description: Creates an asynchronous yt-dlp-backed subtitle extraction job for one YouTube video.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeVideoId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/YoutubeSubtitleJobCreateRequest"
      responses:
        "202":
          description: YouTube subtitle job accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMediaJobResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/videos/{video_id}/comments:
    get:
      tags:
        - YouTube
      operationId: listYoutubeVideoComments
      summary: List YouTube video comments.
      description: Lists ordinary comment records previously produced by YouTube comment jobs.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeVideoId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: YouTube comment records.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeVideoCommentsResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    post:
      tags:
        - YouTube
      operationId: createYoutubeCommentJob
      summary: Create a YouTube comment job.
      description: Creates an asynchronous yt-dlp-backed ordinary comment extraction job for one YouTube video.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeVideoId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/YoutubeCommentJobCreateRequest"
      responses:
        "202":
          description: YouTube comment job accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMediaJobResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/media-jobs/{job_id}:
    get:
      tags:
        - YouTube
      operationId: getYoutubeMediaJob
      summary: Get a YouTube media job.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeMediaJobId"
      responses:
        "200":
          description: YouTube media job.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMediaJobResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMediaNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/media-jobs/{job_id}/artifacts:
    get:
      tags:
        - YouTube
      operationId: listYoutubeMediaJobArtifacts
      summary: List YouTube media job artifacts.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeMediaJobId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: YouTube media artifacts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/YoutubeMediaArtifactListResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/YoutubeMediaNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/youtube/media-jobs/{job_id}/artifacts/{artifact_id}/content:
    get:
      tags:
        - YouTube
      operationId: getYoutubeMediaJobArtifactContent
      summary: Download a YouTube media artifact.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/YoutubeMediaJobId"
        - $ref: "#/components/parameters/YoutubeMediaArtifactId"
      responses:
        "200":
          description: YouTube media artifact content.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
            application/json:
              schema:
                additionalProperties: true
            text/vtt:
              schema:
                type: string
            video/mp4:
              schema:
                type: string
                format: binary
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/ArtifactNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/google-maps/search:
    post:
      tags:
        - Google Maps
      operationId: searchGoogleMaps
      summary: Search Google Maps places.
      description: Runs bounded, low-frequency Google Maps place search over the server-owned direct HTTP protocol.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GoogleMapsSearchRequest"
      responses:
        "200":
          description: Normalized Google Maps search results and page proof.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GoogleMapsSearchResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "502":
          $ref: "#/components/responses/FetchFailed"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/google-maps/place-details:
    post:
      tags:
        - Google Maps
      operationId: getGoogleMapsPlaceDetails
      summary: Get Google Maps place details.
      description: Reads normalized details for one opaque Maps data_id returned by the search endpoint.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GoogleMapsPlaceDetailsRequest"
      responses:
        "200":
          description: Normalized Google Maps place details.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GoogleMapsPlaceDetailsResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/RateLimited"
        "502":
          $ref: "#/components/responses/FetchFailed"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/google-trends/related-queries:
    post:
      tags:
        - Google Trends
      operationId: createGoogleTrendsRelatedQueriesJob
      summary: Create a Google Trends related-queries job.
      description: >
        Accepts one complete Trends grain and queues asynchronous collection.
        Browser profile, CDP, Cookie, reCAPTCHA, and widget-token details stay internal.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GoogleTrendsRelatedQueriesRequest"
      responses:
        "202":
          description: Google Trends job accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GoogleTrendsJobResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "429":
          $ref: "#/components/responses/QuotaExceeded"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /v1/google-trends/jobs/{job_id}:
    get:
      tags:
        - Google Trends
      operationId: getGoogleTrendsJob
      summary: Get a Google Trends job.
      description: Polls one related-queries job and returns only normalized Top/Rising results or a sanitized error.
      security:
        - BearerAuth: []
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Google Trends job state.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GoogleTrendsJobResponse"
        "401":
          $ref: "#/components/responses/AuthenticationRequired"
        "403":
          $ref: "#/components/responses/PermissionDenied"
        "404":
          $ref: "#/components/responses/GoogleTrendsJobNotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >
        Caller-generated key for replay-safe creation. Reusing the key with the
        same request body returns the stored response; reusing it with a
        different body or while the original request is in progress returns 409.
      schema:
        type: string
        minLength: 1
        maxLength: 255
    CrawlId:
      name: crawl_id
      in: path
      required: true
      schema:
        type: string
    RunId:
      name: run_id
      in: path
      required: true
      schema:
        type: string
    SessionId:
      name: session_id
      in: path
      required: true
      schema:
        type: string
    ProfileId:
      name: profile_id
      in: path
      required: true
      schema:
        type: string
    MonitorId:
      name: monitor_id
      in: path
      required: true
      schema:
        type: string
    YoutubeVideoId:
      name: video_id
      in: path
      required: true
      schema:
        type: string
    YoutubeMediaJobId:
      name: job_id
      in: path
      required: true
      schema:
        type: string
    YoutubeMediaArtifactId:
      name: artifact_id
      in: path
      required: true
      schema:
        type: string
    Limit:
      name: limit
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
    Cursor:
      name: cursor
      in: query
      required: false
      schema:
        type:
          - string
          - "null"
    Status:
      name: status
      in: query
      required: false
      schema:
        $ref: "#/components/schemas/PublicStatus"
  responses:
    ValidationError:
      description: Request validation failed.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    AuthenticationRequired:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    PermissionDenied:
      description: Authenticated principal cannot access this resource.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    Timeout:
      description: Work timed out.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    IdempotencyConflict:
      description: The idempotency key is already in progress or belongs to a different request body.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    RunNotFound:
      description: Run was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    CrawlNotFound:
      description: Crawl was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    ArtifactNotFound:
      description: Artifact was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    SessionNotFound:
      description: Browser session was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    ProfileNotFound:
      description: Browser profile was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    YoutubeMonitorNotFound:
      description: YouTube monitor was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    RedditMonitorNotFound:
      description: Reddit monitor was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    YoutubeMediaNotFound:
      description: YouTube media job was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    GoogleTrendsJobNotFound:
      description: Google Trends job was not found or is not visible to this workspace.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    ArtifactExpired:
      description: Artifact retention expired.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    QuotaExceeded:
      description: Monthly quota was exhausted.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    RateLimited:
      description: Temporary rate limit.
      headers:
        Retry-After:
          schema:
            type: string
          description: Delay before retrying.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    FetchFailed:
      description: Upstream fetch or network failure.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    RenderFailed:
      description: Browser render failed.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
    ServiceUnavailable:
      description: Required runtime service is unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PublicErrorResponse"
  schemas:
    FetchRequest:
      type: object
      additionalProperties: false
      required:
        - url
      properties:
        url:
          type: string
          format: uri
    BrowserScrapeRequest:
      allOf:
        - $ref: "#/components/schemas/FetchRequest"
        - type: object
          additionalProperties: false
          properties:
            output:
              $ref: "#/components/schemas/OutputOptions"
            browser:
              $ref: "#/components/schemas/BrowserOptions"
            extraction:
              $ref: "#/components/schemas/StructuredExtractionRequest"
    ExtractRequest:
      type: object
      additionalProperties: false
      required:
        - url
        - html
        - extraction
      properties:
        url:
          type: string
          format: uri
        html:
          type: string
          minLength: 1
          maxLength: 2000000
        extraction:
          $ref: "#/components/schemas/StructuredExtractionRequest"
    CrawlCreateRequest:
      type: object
      additionalProperties: false
      required:
        - urls
      properties:
        urls:
          type: array
          minItems: 1
          maxItems: 100
          description: >
            Seed URLs for the crawl. Each URL must use HTTP or HTTPS and must
            not contain URL userinfo (a username or password).
          items:
            type: string
            format: uri
        max_depth:
          type: integer
          minimum: 0
          default: 0
        scope:
          type: string
          enum:
            - same_hostname
            - same_domain
            - same_origin
            - all
          default: same_hostname
          description: >-
            scope defaults to same_hostname. same_hostname follows only the
            exact hostname. same_domain follows hosts sharing the same
            registrable domain, including subdomains. same_origin additionally
            requires the same scheme and effective port. all accepts any valid
            HTTP(S) URL.
        discover_sitemap:
          type: boolean
          default: false
        sitemap_url:
          type:
            - string
            - "null"
          format: uri
          description: >
            Optional explicit sitemap URL. It must use HTTP or HTTPS and must
            not contain URL userinfo (a username or password).
        sitemap_limit:
          type: integer
          minimum: 1
          maximum: 10000
          default: 1000
        browser:
          $ref: "#/components/schemas/BrowserOptions"
        extraction:
          $ref: "#/components/schemas/StructuredExtractionRequest"
    OutputOptions:
      type: object
      additionalProperties: false
      properties:
        screenshot:
          $ref: "#/components/schemas/ScreenshotOptions"
        recording:
          $ref: "#/components/schemas/RecordingOptions"
    ScreenshotOptions:
      type: object
      additionalProperties: false
      properties:
        enabled:
          type: boolean
          default: false
        format:
          type: string
          enum:
            - png
          default: png
        full_page:
          type: boolean
          default: false
    RecordingOptions:
      type: object
      additionalProperties: false
      properties:
        enabled:
          type: boolean
          default: false
        format:
          type: string
          enum:
            - mp4
            - webm
          default: mp4
      description: >
        Requests recording artifact capture when supported by the configured
        browser runtime. Recording downloads are exposed only as run artifacts;
        clients should download only recording artifact keys returned on the
        run. This does not imply full Browserless protocol compatibility or
        provider-native recording capture.
    BrowserOptions:
      type: object
      additionalProperties: false
      description: >
        Safe browser-render controls. These map to Spider human_behavior policy
        and do not expose arbitrary JavaScript, cookies, storage state, proxy
        URLs, user agents, or DICloak profile IDs.
      properties:
        wait_for_selector:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 1024
          description: CSS selector that must appear before returning the rendered page.
        wait_for_timeout_ms:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 15000
          description: Maximum wait for `wait_for_selector`, in milliseconds.
        process_iframes:
          type: boolean
          default: false
          description: Include same-origin iframe content where the renderer can safely access it.
        flatten_shadow_dom:
          type: boolean
          default: false
          description: Flatten open shadow DOM content into the rendered document output.
        virtual_scroll:
          $ref: "#/components/schemas/VirtualScrollOptions"
    VirtualScrollOptions:
      type: object
      additionalProperties: false
      required:
        - container_selector
      properties:
        container_selector:
          type: string
          minLength: 1
          maxLength: 1024
          description: CSS selector for the scrollable container.
        scroll_count:
          type: integer
          minimum: 1
          maximum: 50
          default: 10
        scroll_by:
          anyOf:
            - type: string
              enum:
                - container_height
                - page_height
            - type: integer
              minimum: 1
              maximum: 20000
          default: container_height
        wait_after_scroll:
          type: number
          minimum: 0
          maximum: 5
          default: 0.5
    StructuredExtractionRequest:
      type: object
      additionalProperties: false
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - json_css
            - llm
        schema:
          $ref: "#/components/schemas/JsonCssExtractionSchema"
        raw_crawl4ai_schema:
          type:
            - object
            - "null"
          additionalProperties: true
          description: >
            Allowlisted raw Crawl4AI JsonCssExtractionStrategy schema. Only
            JSON schema keys for name, baseSelector, baseFields, fields,
            selector, source, default, scalar/list/nested field types, regex,
            and safe transforms are accepted. function/expression hooks are
            rejected.
        computed_fields:
          type: array
          maxItems: 100
          default: []
          items:
            $ref: "#/components/schemas/StructuredComputedField"
        llm:
          anyOf:
            - $ref: "#/components/schemas/StructuredLLMExtractionOptions"
            - type: "null"
    JsonCssExtractionSchema:
      type: object
      additionalProperties: false
      required:
        - base_selector
        - fields
      properties:
        name:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 128
        base_selector:
          type: string
          minLength: 1
          maxLength: 1024
        fields:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: "#/components/schemas/StructuredExtractionField"
    StructuredExtractionField:
      type: object
      additionalProperties: false
      required:
        - name
        - type
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 128
        selector:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 1024
        type:
          type: string
          enum:
            - text
            - html
            - attribute
            - regex
            - nested
            - list
            - nested_list
        attribute:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 128
        pattern:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 1024
        group:
          type:
            - integer
            - "null"
          minimum: 0
        transform:
          type:
            - string
            - "null"
          enum:
            - strip
            - lowercase
            - uppercase
        fields:
          anyOf:
            - type: array
              minItems: 1
              maxItems: 100
              items:
                $ref: "#/components/schemas/StructuredExtractionField"
            - type: "null"
    StructuredComputedField:
      type: object
      additionalProperties: false
      required:
        - name
        - operation
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 128
        operation:
          type: string
          enum:
            - template
            - join
            - first_non_empty
          default: template
        sources:
          type: array
          maxItems: 20
          default: []
          items:
            type: string
            pattern: "^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[[0-9]{1,4}\\])*$"
        template:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 2048
        separator:
          type: string
          maxLength: 128
          default: ""
        default:
          type:
            - string
            - "null"
          maxLength: 2048
        transform:
          type:
            - string
            - "null"
          enum:
            - strip
            - lowercase
            - uppercase
    StructuredLLMExtractionOptions:
      type: object
      additionalProperties: false
      properties:
        name:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 128
        instruction:
          type: string
          minLength: 1
          maxLength: 4096
        schema:
          type:
            - object
            - "null"
          additionalProperties: true
          description: JSON Schema-style target shape sent to the server-configured LLM.
        extraction_type:
          type: string
          enum:
            - schema
            - block
          default: schema
        input_format:
          type: string
          enum:
            - html
            - markdown
            - text
            - fit_html
          default: html
        chunk_token_threshold:
          type: integer
          minimum: 128
          maximum: 200000
          default: 4096
        overlap_rate:
          type: number
          minimum: 0
          maximum: 0.5
          default: 0.1
        apply_chunking:
          type: boolean
          default: true
        force_json_response:
          type: boolean
          default: true
        temperature:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 2
        max_tokens:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 128000
    BrowserSessionsResponse:
      type: object
      additionalProperties: false
      required:
        - items
        - capability
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/BrowserSession"
        capability:
          $ref: "#/components/schemas/PublicCapability"
    BrowserSession:
      type: object
      additionalProperties: false
      required:
        - id
        - status
      properties:
        id:
          type: string
        status:
          type: string
        created_at:
          type:
            - string
            - "null"
          format: date-time
        expires_at:
          type:
            - string
            - "null"
          format: date-time
        profile_id:
          type:
            - string
            - "null"
    BrowserSessionCreateRequest:
      type: object
      additionalProperties: false
      properties:
        ttl_seconds:
          type: integer
          minimum: 30
          maximum: 3600
          default: 300
        device_profile:
          type: string
          description: When profile pools are configured, auto resolves desktop-first in windows -> macos -> linux order; mobile pools require explicit android or ios.
          enum:
            - auto
            - windows
            - macos
            - linux
            - android
            - ios
          default: auto
        domain:
          type:
            - string
            - "null"
          maxLength: 255
    BrowserSessionCreateResponse:
      type: object
      additionalProperties: false
      required:
        - session
        - connect_url
      properties:
        session:
          $ref: "#/components/schemas/BrowserSession"
        connect_url:
          type: string
    BrowserSessionResponse:
      type: object
      additionalProperties: false
      required:
        - session
      properties:
        session:
          $ref: "#/components/schemas/BrowserSession"
    BrowserSessionConnectResponse:
      type: object
      additionalProperties: false
      required:
        - session_id
        - websocket_url
      properties:
        session_id:
          type: string
        websocket_url:
          type: string
        expires_at:
          type:
            - string
            - "null"
          format: date-time
    BrowserSessionStopResponse:
      type: object
      additionalProperties: false
      required:
        - id
        - stopped
        - lease_ids
        - errors
      properties:
        id:
          type: string
        stopped:
          type: boolean
        lease_ids:
          type: array
          items:
            type: string
        errors:
          type: object
          additionalProperties:
            type: string
    BrowserProfilesResponse:
      type: object
      additionalProperties: false
      required:
        - items
        - capability
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/BrowserProfile"
        capability:
          $ref: "#/components/schemas/PublicCapability"
    BrowserProfilePoolsResponse:
      type: object
      additionalProperties: false
      required:
        - items
        - capability
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/BrowserProfilePool"
        capability:
          $ref: "#/components/schemas/PublicCapability"
    BrowserProfile:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - status
      properties:
        id:
          type: string
        name:
          type: string
        created_at:
          type:
            - string
            - "null"
          format: date-time
        last_used_at:
          type:
            - string
            - "null"
          format: date-time
        status:
          type: string
        device_profile:
          type:
            - string
            - "null"
        member_count:
          type: integer
          minimum: 0
        available:
          type: boolean
    BrowserProfilePool:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - status
      properties:
        id:
          type: string
        name:
          type: string
        created_at:
          type:
            - string
            - "null"
          format: date-time
        last_synced_at:
          type:
            - string
            - "null"
          format: date-time
        status:
          type: string
        device_profile:
          type:
            - string
            - "null"
        member_count:
          type: integer
          minimum: 0
        available:
          type: boolean
    BrowserProfileCreateRequest:
      type: object
      additionalProperties: false
      required:
        - id
        - name
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 64
        name:
          type: string
          minLength: 1
          maxLength: 128
        device_profile:
          type: string
          enum:
            - auto
            - windows
            - macos
            - linux
            - android
            - ios
          default: auto
        desired_count:
          type: integer
          minimum: 0
          maximum: 100
          default: 1
        enabled:
          type: boolean
          default: true
    BrowserProfileUpdateRequest:
      type: object
      additionalProperties: false
      properties:
        name:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 128
        device_profile:
          type:
            - string
            - "null"
          enum:
            - auto
            - windows
            - macos
            - linux
            - android
            - ios
            - null
        desired_count:
          type:
            - integer
            - "null"
          minimum: 0
          maximum: 100
        enabled:
          type:
            - boolean
            - "null"
    BrowserProfileResponse:
      type: object
      additionalProperties: false
      required:
        - profile
      properties:
        profile:
          $ref: "#/components/schemas/BrowserProfile"
    BrowserProfileDeleteResponse:
      type: object
      additionalProperties: false
      required:
        - id
        - deleted
      properties:
        id:
          type: string
        deleted:
          type: boolean
    PublicCapability:
      type: object
      additionalProperties: false
      required:
        - available
      properties:
        available:
          type: boolean
        reason:
          type: string
    PageRunResponse:
      type: object
      additionalProperties: false
      required:
        - run
        - result
      properties:
        run:
          $ref: "#/components/schemas/PublicRun"
        result:
          $ref: "#/components/schemas/PublicPageResult"
    CrawlCreateResponse:
      type: object
      additionalProperties: false
      required:
        - run
        - crawl
      properties:
        run:
          $ref: "#/components/schemas/PublicRun"
        crawl:
          $ref: "#/components/schemas/PublicCrawl"
    CrawlStatusResponse:
      type: object
      additionalProperties: false
      required:
        - crawl
      properties:
        crawl:
          $ref: "#/components/schemas/PublicCrawl"
    CrawlResultsResponse:
      type: object
      additionalProperties: false
      required:
        - crawl
        - items
      properties:
        crawl:
          $ref: "#/components/schemas/PublicCrawl"
        items:
          type: array
          items:
            $ref: "#/components/schemas/PublicPageResult"
        next_cursor:
          type:
            - string
            - "null"
    CrawlItemsResponse:
      type: object
      additionalProperties: false
      required:
        - crawl
        - items
      properties:
        crawl:
          $ref: "#/components/schemas/PublicCrawl"
        items:
          type: array
          items:
            $ref: "#/components/schemas/PublicCrawlItem"
        next_cursor:
          type:
            - string
            - "null"
    PublicCrawlItem:
      type: object
      additionalProperties: false
      required:
        - crawl_id
        - run_id
        - page_url
        - position
        - data
      properties:
        crawl_id:
          type: string
        run_id:
          type: string
        page_url:
          type: string
          format: uri
        final_url:
          type:
            - string
            - "null"
          format: uri
        schema_name:
          type:
            - string
            - "null"
        position:
          type: integer
          minimum: 0
        data:
          type: object
          additionalProperties: true
    CrawlRunResponse:
      type: object
      additionalProperties: false
      required:
        - run
        - crawl
      properties:
        run:
          $ref: "#/components/schemas/PublicRun"
        crawl:
          $ref: "#/components/schemas/PublicCrawl"
    ListRunsResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/PublicRun"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeMonitorStrategy:
      type: string
      enum:
        - rss
        - yt_dlp_polling
        - auto
    YoutubeMonitorBackendStrategy:
      type: string
      enum:
        - rss
        - yt_dlp_polling
    YoutubeMonitorCreateRequest:
      type: object
      additionalProperties: false
      properties:
        channel_id:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 255
        channel_url:
          type:
            - string
            - "null"
          format: uri
        rss_url:
          type:
            - string
            - "null"
          format: uri
        strategy:
          type: string
          enum:
            - rss
            - yt_dlp_polling
            - auto
          default: rss
        enabled:
          type: boolean
          default: true
        check_interval_seconds:
          type: number
          minimum: 60
          maximum: 86400
          default: 900
        slow_check_interval_seconds:
          type: number
          minimum: 300
          maximum: 604800
          default: 43200
        max_items:
          type: integer
          minimum: 1
          maximum: 10000
          default: 100
        quiet_first_check:
          type: boolean
          default: true
        quiet_start:
          type: boolean
          default: false
        track_reschedule:
          type: boolean
          default: false
    YoutubeMonitorPatchRequest:
      type: object
      additionalProperties: false
      properties:
        channel_id:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 255
        channel_url:
          type:
            - string
            - "null"
          format: uri
        rss_url:
          type:
            - string
            - "null"
          format: uri
        strategy:
          anyOf:
            - $ref: "#/components/schemas/YoutubeMonitorStrategy"
            - type: "null"
        enabled:
          type:
            - boolean
            - "null"
        check_interval_seconds:
          type:
            - number
            - "null"
          minimum: 60
          maximum: 86400
        slow_check_interval_seconds:
          type:
            - number
            - "null"
          minimum: 300
          maximum: 604800
        max_items:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 10000
        quiet_first_check:
          type:
            - boolean
            - "null"
        quiet_start:
          type:
            - boolean
            - "null"
        track_reschedule:
          type:
            - boolean
            - "null"
    YoutubeMonitorListResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeMonitor"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeMonitorResponse:
      type: object
      additionalProperties: false
      required:
        - monitor
      properties:
        monitor:
          $ref: "#/components/schemas/YoutubeMonitor"
    YoutubeMonitorCheckResponse:
      type: object
      additionalProperties: false
      required:
        - monitor
        - events
      properties:
        monitor:
          $ref: "#/components/schemas/YoutubeMonitor"
        events:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeMonitorEvent"
    YoutubeMonitorEventsResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeMonitorEvent"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeMonitorVideosResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeVideo"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeDownloadJobCreateRequest:
      type: object
      additionalProperties: false
      properties:
        format:
          type: string
          default: bestvideo*+bestaudio/best
        audio_only:
          type: boolean
          default: false
        include_info_json:
          type: boolean
          default: true
        include_thumbnail:
          type: boolean
          default: true
        include_subtitles:
          type: boolean
          default: false
        subtitle_languages:
          type: array
          items:
            type: string
          default: []
        include_auto_subtitles:
          type: boolean
          default: false
    YoutubeSubtitleJobCreateRequest:
      type: object
      additionalProperties: false
      properties:
        languages:
          type: array
          items:
            type: string
          default:
            - en
        include_auto:
          type: boolean
          default: true
        format:
          type: string
          enum:
            - vtt
            - srt
            - json3
            - best
          default: vtt
    YoutubeCommentJobCreateRequest:
      type: object
      additionalProperties: false
      properties:
        max_items:
          type: integer
          minimum: 1
          maximum: 10000
          default: 100
        sort:
          type: string
          enum:
            - top
            - newest
          default: top
        include_replies:
          type: boolean
          default: true
    YoutubeMediaJobResponse:
      type: object
      additionalProperties: false
      required:
        - job
      properties:
        job:
          $ref: "#/components/schemas/YoutubeMediaJob"
    YoutubeMediaJob:
      type: object
      additionalProperties: false
      required:
        - id
        - platform
        - kind
        - status
        - video_id
        - video_url
        - progress
      properties:
        id:
          type: string
        platform:
          type: string
          enum:
            - youtube
        kind:
          type: string
          enum:
            - download
            - subtitles
            - comments
        status:
          type: string
          enum:
            - queued
            - running
            - completed
            - failed
            - canceled
        video_id:
          type: string
        video_url:
          type: string
        progress:
          $ref: "#/components/schemas/YoutubeMediaProgress"
        error:
          anyOf:
            - $ref: "#/components/schemas/YoutubeMediaError"
            - type: "null"
        created_at:
          type:
            - string
            - "null"
          format: date-time
        updated_at:
          type:
            - string
            - "null"
          format: date-time
        started_at:
          type:
            - string
            - "null"
          format: date-time
        finished_at:
          type:
            - string
            - "null"
          format: date-time
    YoutubeMediaProgress:
      type: object
      additionalProperties: false
      required:
        - stage
      properties:
        stage:
          type: string
        percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
        downloaded_bytes:
          type:
            - integer
            - "null"
          minimum: 0
        total_bytes:
          type:
            - integer
            - "null"
          minimum: 0
        speed_bytes_per_second:
          type:
            - number
            - "null"
          minimum: 0
    YoutubeMediaError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
        retryable:
          type: boolean
          default: false
    YoutubeMediaArtifactListResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeMediaArtifact"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeMediaArtifact:
      type: object
      additionalProperties: false
      required:
        - id
        - job_id
        - video_id
        - type
        - filename
        - content_type
        - url
      properties:
        id:
          type: string
        job_id:
          type: string
        video_id:
          type: string
        type:
          type: string
          enum:
            - video
            - audio
            - subtitle
            - thumbnail
            - info_json
            - comments_json
        filename:
          type: string
        content_type:
          type: string
        size_bytes:
          type:
            - integer
            - "null"
          minimum: 0
        language:
          type:
            - string
            - "null"
        format:
          type:
            - string
            - "null"
        url:
          type: string
        created_at:
          type:
            - string
            - "null"
          format: date-time
    YoutubeVideoSubtitlesResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeSubtitle"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeSubtitle:
      type: object
      additionalProperties: false
      required:
        - id
        - job_id
        - video_id
        - language
        - source
        - format
        - artifact
      properties:
        id:
          type: string
        job_id:
          type: string
        video_id:
          type: string
        language:
          type: string
        source:
          type: string
          enum:
            - manual
            - automatic
        format:
          type: string
        artifact:
          $ref: "#/components/schemas/YoutubeMediaArtifact"
        created_at:
          type:
            - string
            - "null"
          format: date-time
    YoutubeVideoCommentsResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeComment"
        next_cursor:
          type:
            - string
            - "null"
    YoutubeComment:
      type: object
      additionalProperties: false
      required:
        - id
        - job_id
        - video_id
        - text
      properties:
        id:
          type: string
        job_id:
          type: string
        video_id:
          type: string
        parent_id:
          type:
            - string
            - "null"
        author:
          type:
            - string
            - "null"
        author_channel_id:
          type:
            - string
            - "null"
        text:
          type: string
        like_count:
          type:
            - integer
            - "null"
          minimum: 0
        published_at:
          type:
            - string
            - "null"
          format: date-time
        is_pinned:
          type: boolean
          default: false
        created_at:
          type:
            - string
            - "null"
          format: date-time
    YoutubeMonitor:
      type: object
      additionalProperties: false
      required:
        - id
        - platform
        - status
        - strategy
        - target
        - settings
        - checks
      properties:
        id:
          type: string
        platform:
          type: string
          enum:
            - youtube
        status:
          type: string
          enum:
            - active
            - paused
        strategy:
          $ref: "#/components/schemas/YoutubeMonitorStrategy"
        target:
          $ref: "#/components/schemas/YoutubeMonitorTarget"
        settings:
          $ref: "#/components/schemas/YoutubeMonitorSettings"
        checks:
          type: array
          items:
            $ref: "#/components/schemas/YoutubeMonitorCheckState"
        created_at:
          type:
            - string
            - "null"
          format: date-time
        updated_at:
          type:
            - string
            - "null"
          format: date-time
    YoutubeMonitorTarget:
      type: object
      additionalProperties: false
      properties:
        channel_id:
          type:
            - string
            - "null"
        channel_url:
          type:
            - string
            - "null"
        rss_url:
          type:
            - string
            - "null"
    YoutubeMonitorSettings:
      type: object
      additionalProperties: false
      required:
        - check_interval_seconds
        - slow_check_interval_seconds
        - max_items
        - quiet_first_check
        - quiet_start
        - track_reschedule
      properties:
        check_interval_seconds:
          type: number
        slow_check_interval_seconds:
          type: number
        max_items:
          type: integer
        quiet_first_check:
          type: boolean
        quiet_start:
          type: boolean
        track_reschedule:
          type: boolean
    YoutubeMonitorCheckState:
      type: object
      additionalProperties: false
      required:
        - strategy
        - status
      properties:
        strategy:
          $ref: "#/components/schemas/YoutubeMonitorBackendStrategy"
        status:
          type: string
          enum:
            - never_run
            - completed
            - failed
            - not_modified
        next_check_at:
          type:
            - string
            - "null"
          format: date-time
        last_checked_at:
          type:
            - string
            - "null"
          format: date-time
        last_error_code:
          type:
            - string
            - "null"
    YoutubeMonitorEvent:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - monitor_id
        - observed_at
      properties:
        id:
          type: string
        type:
          type: string
          enum:
            - new_video
            - updated_video
            - rescheduled_video
            - monitor_error
        monitor_id:
          type: string
        strategy:
          anyOf:
            - $ref: "#/components/schemas/YoutubeMonitorBackendStrategy"
            - type: "null"
        video_id:
          type:
            - string
            - "null"
        video:
          anyOf:
            - $ref: "#/components/schemas/YoutubeVideo"
            - type: "null"
        previous_video:
          anyOf:
            - $ref: "#/components/schemas/YoutubeVideo"
            - type: "null"
        error:
          anyOf:
            - $ref: "#/components/schemas/YoutubeMonitorEventError"
            - type: "null"
        observed_at:
          type: string
          format: date-time
    YoutubeMonitorEventError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - retryable
      properties:
        code:
          type: string
        message:
          type: string
        retryable:
          type: boolean
    YoutubeVideo:
      type: object
      additionalProperties: false
      required:
        - video_id
        - url
        - title
      properties:
        video_id:
          type: string
        url:
          type: string
        title:
          type: string
        description:
          type:
            - string
            - "null"
        thumbnail_url:
          type:
            - string
            - "null"
        published_at:
          type:
            - string
            - "null"
          format: date-time
        scheduled_at:
          type:
            - string
            - "null"
          format: date-time
        updated_at:
          type:
            - string
            - "null"
          format: date-time
        channel_id:
          type:
            - string
            - "null"
        author:
          type:
            - string
            - "null"
        live_status:
          type:
            - string
            - "null"
        view_count:
          type:
            - integer
            - "null"
        first_seen_at:
          type:
            - string
            - "null"
          format: date-time
        last_seen_at:
          type:
            - string
            - "null"
          format: date-time
    RedditMonitorStrategy:
      type: string
      enum:
        - json_fetch
    RedditListingSort:
      type: string
      enum:
        - hot
        - new
        - top
        - rising
    RedditMonitorCreateRequest:
      type: object
      additionalProperties: false
      required:
        - subreddit
      properties:
        subreddit:
          type: string
          minLength: 1
          maxLength: 255
        target_url:
          type:
            - string
            - "null"
          format: uri
        strategy:
          type: string
          enum:
            - json_fetch
          default: json_fetch
        sort:
          $ref: "#/components/schemas/RedditListingSort"
          default: new
        time_filter:
          type:
            - string
            - "null"
          maxLength: 32
        enabled:
          type: boolean
          default: true
        check_interval_seconds:
          type: number
          minimum: 300
          maximum: 86400
          default: 900
        max_items:
          type: integer
          minimum: 1
          maximum: 100
          default: 100
        quiet_first_check:
          type: boolean
          default: true
        quiet_start:
          type: boolean
          default: false
        warmup_cookie_max_age_seconds:
          type: integer
          minimum: 300
          maximum: 2592000
          default: 86400
    RedditMonitorPatchRequest:
      type: object
      additionalProperties: false
      properties:
        subreddit:
          type:
            - string
            - "null"
          minLength: 1
          maxLength: 255
        target_url:
          type:
            - string
            - "null"
          format: uri
        sort:
          anyOf:
            - $ref: "#/components/schemas/RedditListingSort"
            - type: "null"
        time_filter:
          type:
            - string
            - "null"
          maxLength: 32
        enabled:
          type:
            - boolean
            - "null"
        check_interval_seconds:
          type:
            - number
            - "null"
          minimum: 300
          maximum: 86400
        max_items:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 100
        quiet_first_check:
          type:
            - boolean
            - "null"
        quiet_start:
          type:
            - boolean
            - "null"
        warmup_cookie_max_age_seconds:
          type:
            - integer
            - "null"
          minimum: 300
          maximum: 2592000
    RedditMonitorListResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/RedditMonitor"
        next_cursor:
          type:
            - string
            - "null"
    RedditMonitorResponse:
      type: object
      additionalProperties: false
      required:
        - monitor
      properties:
        monitor:
          $ref: "#/components/schemas/RedditMonitor"
    RedditMonitorCheckResponse:
      type: object
      additionalProperties: false
      required:
        - monitor
        - events
      properties:
        monitor:
          $ref: "#/components/schemas/RedditMonitor"
        events:
          type: array
          items:
            $ref: "#/components/schemas/RedditMonitorEvent"
    RedditMonitorEventsResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/RedditMonitorEvent"
        next_cursor:
          type:
            - string
            - "null"
    RedditMonitorPostsResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/RedditPost"
        next_cursor:
          type:
            - string
            - "null"
    RedditMonitor:
      type: object
      additionalProperties: false
      required:
        - id
        - platform
        - status
        - strategy
        - target
        - settings
        - checks
      properties:
        id:
          type: string
        platform:
          type: string
          enum:
            - reddit
        status:
          type: string
          enum:
            - active
            - paused
        strategy:
          $ref: "#/components/schemas/RedditMonitorStrategy"
        target:
          $ref: "#/components/schemas/RedditMonitorTarget"
        settings:
          $ref: "#/components/schemas/RedditMonitorSettings"
        checks:
          type: array
          items:
            $ref: "#/components/schemas/RedditMonitorCheckState"
        created_at:
          type:
            - string
            - "null"
          format: date-time
        updated_at:
          type:
            - string
            - "null"
          format: date-time
    RedditMonitorTarget:
      type: object
      additionalProperties: false
      required:
        - subreddit
      properties:
        subreddit:
          type: string
        target_url:
          type:
            - string
            - "null"
    RedditMonitorSettings:
      type: object
      additionalProperties: false
      required:
        - check_interval_seconds
        - max_items
        - quiet_first_check
        - quiet_start
        - sort
        - warmup_cookie_max_age_seconds
      properties:
        check_interval_seconds:
          type: number
        max_items:
          type: integer
        quiet_first_check:
          type: boolean
        quiet_start:
          type: boolean
        sort:
          $ref: "#/components/schemas/RedditListingSort"
        time_filter:
          type:
            - string
            - "null"
        warmup_cookie_max_age_seconds:
          type: integer
    RedditMonitorCheckState:
      type: object
      additionalProperties: false
      required:
        - strategy
        - status
      properties:
        strategy:
          $ref: "#/components/schemas/RedditMonitorStrategy"
        status:
          type: string
          enum:
            - never_run
            - completed
            - failed
            - not_modified
        next_check_at:
          type:
            - string
            - "null"
          format: date-time
        last_checked_at:
          type:
            - string
            - "null"
          format: date-time
        last_error_code:
          type:
            - string
            - "null"
    RedditMonitorEvent:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - monitor_id
        - observed_at
      properties:
        id:
          type: string
        type:
          type: string
          enum:
            - new_post
            - updated_post
            - monitor_error
        monitor_id:
          type: string
        strategy:
          anyOf:
            - $ref: "#/components/schemas/RedditMonitorStrategy"
            - type: "null"
        post_id:
          type:
            - string
            - "null"
        post:
          anyOf:
            - $ref: "#/components/schemas/RedditPost"
            - type: "null"
        previous_post:
          anyOf:
            - $ref: "#/components/schemas/RedditPost"
            - type: "null"
        error:
          anyOf:
            - $ref: "#/components/schemas/RedditMonitorEventError"
            - type: "null"
        observed_at:
          type: string
          format: date-time
    RedditMonitorEventError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - retryable
      properties:
        code:
          type: string
        message:
          type: string
        retryable:
          type: boolean
    RedditPost:
      type: object
      additionalProperties: false
      required:
        - fullname
        - post_id
        - subreddit
        - url
        - title
      properties:
        fullname:
          type: string
        post_id:
          type: string
        subreddit:
          type: string
        url:
          type: string
        title:
          type: string
        author:
          type:
            - string
            - "null"
        selftext:
          type:
            - string
            - "null"
        published_at:
          type:
            - string
            - "null"
          format: date-time
        score:
          type:
            - integer
            - "null"
        num_comments:
          type:
            - integer
            - "null"
        first_seen_at:
          type:
            - string
            - "null"
          format: date-time
        last_seen_at:
          type:
            - string
            - "null"
          format: date-time
    PublicRun:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - status
        - quota
      properties:
        id:
          type: string
        type:
          $ref: "#/components/schemas/PublicRunType"
        status:
          $ref: "#/components/schemas/PublicStatus"
        created_at:
          type:
            - string
            - "null"
          format: date-time
        completed_at:
          type:
            - string
            - "null"
          format: date-time
        cost_units:
          type:
            - integer
            - "null"
          minimum: 0
        quota:
          $ref: "#/components/schemas/PublicQuotaReservation"
    PublicRunType:
      type: string
      enum:
        - fetch
        - browser_scrape
        - crawl
    PublicStatus:
      type: string
      enum:
        - queued
        - running
        - paused
        - completed
        - failed
        - low_quality
        - budget_exhausted
        - expired
    PublicQuotaReservation:
      type: object
      additionalProperties: false
      required:
        - resource
        - quantity_reserved
      properties:
        resource:
          type: string
          enum:
            - scrape
            - crawl
        quantity_reserved:
          type: integer
          minimum: 1
    PublicPageResult:
      type: object
      additionalProperties: false
      required:
        - url
        - status
        - content
        - artifacts
        - audit
        - usage
      properties:
        url:
          type: string
          format: uri
        final_url:
          type:
            - string
            - "null"
          format: uri
        status:
          $ref: "#/components/schemas/PublicStatus"
        title:
          type:
            - string
            - "null"
        content:
          $ref: "#/components/schemas/PublicContent"
        structured:
          anyOf:
            - $ref: "#/components/schemas/StructuredExtractionResult"
            - type: "null"
        artifacts:
          type: array
          items:
            $ref: "#/components/schemas/PublicArtifactLink"
        audit:
          $ref: "#/components/schemas/PublicAudit"
        usage:
          $ref: "#/components/schemas/PublicUsage"
        diagnostics:
          $ref: "#/components/schemas/PublicPageDiagnostics"
    ExtractResponse:
      type: object
      additionalProperties: false
      required:
        - url
        - structured
        - usage
      properties:
        url:
          type: string
          format: uri
        structured:
          $ref: "#/components/schemas/StructuredExtractionResult"
        usage:
          $ref: "#/components/schemas/PublicUsage"
    PublicContent:
      type: object
      additionalProperties: false
      properties:
        markdown:
          type:
            - string
            - "null"
        html:
          type:
            - string
            - "null"
        metadata:
          type: object
          additionalProperties:
            type: string
        links:
          type: array
          items:
            type: string
            format: uri
    PublicArtifactLink:
      type: object
      additionalProperties: false
      required:
        - key
        - url
        - content_type
      properties:
        key:
          $ref: "#/components/schemas/ArtifactKey"
        url:
          type: string
        content_type:
          type: string
        expires_at:
          type:
            - string
            - "null"
          format: date-time
    ArtifactKey:
      type: string
      enum:
        - markdown
        - html
        - raw_html
        - screenshot_png
        - recording_mp4
        - recording_webm
        - structured_json
    StructuredExtractionResult:
      type: object
      additionalProperties: false
      required:
        - type
        - source
        - items
        - item_count
      properties:
        type:
          type: string
          enum:
            - json_css
        source:
          type: string
          enum:
            - crawl4ai
        schema_name:
          type:
            - string
            - "null"
        items:
          type: array
          items:
            type: object
            additionalProperties: true
        item_count:
          type: integer
          minimum: 0
        usage:
          anyOf:
            - $ref: "#/components/schemas/StructuredExtractionUsage"
            - type: "null"
        error:
          anyOf:
            - $ref: "#/components/schemas/StructuredExtractionError"
            - type: "null"
    StructuredExtractionUsage:
      type: object
      additionalProperties: false
      required:
        - provider
      properties:
        provider:
          type: string
          enum:
            - server_configured
        prompt_tokens:
          type:
            - integer
            - "null"
          minimum: 0
        completion_tokens:
          type:
            - integer
            - "null"
          minimum: 0
        total_tokens:
          type:
            - integer
            - "null"
          minimum: 0
    StructuredExtractionError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum:
            - structured_extraction_failed
        message:
          type: string
    PublicAudit:
      type: object
      additionalProperties: false
      properties:
        engine_winner:
          type:
            - string
            - "null"
        engines_attempted:
          type: array
          items:
            type: string
        fallback_reasons:
          type: array
          items:
            type: string
        fallback_events:
          type: array
          items:
            type: string
        retry_stats:
          type: object
          additionalProperties: true
        quality_score:
          type:
            - number
            - "null"
        block_reason:
          type:
            - string
            - "null"
          description: >-
            Sanitized execution stop category. Known response guard outcomes
            include body_size_limit, redirect_limit, and blocked_target; all
            are non-retryable. blocked_target prevents Browser fallback.
            body_size_limit uses the current server runtime
            default of 10 MiB (10485760 bytes), which is not
            caller-configurable in public v1. The response body and internal
            transport error text are never exposed by this field.
    PublicAdaptiveExtractionDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public sanitized aggregate for adaptive extraction diagnostics. This
        summarizes selector-memory behavior without exposing raw selectors,
        selector memory records, or provider internals.
      properties:
        enabled:
          type: boolean
          default: false
        used:
          type: boolean
          default: false
        action:
          type: string
          enum:
            - disabled
            - none
            - saved
            - reused
            - relocated
            - skipped_low_quality
            - no_candidate
          default: disabled
        confidence:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 1
    PublicContentQualityDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public sanitized aggregate for content quality diagnostics. The score is
        normalized to 0..1 and does not expose raw extractor internals,
        provider internals, or audit rows.
      properties:
        score:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 1
        confidence:
          type: string
          enum:
            - unknown
            - low
            - medium
            - high
          default: unknown
    PublicBrowserDebugDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public sanitized browser debug capture summary. It exposes only whether
        browser debug capture produced a summary plus aggregate network and
        console counts. Raw URLs, headers, cookies, bearer tokens, proxy
        credentials, CDP URLs, response bodies, status/resource/console-level
        buckets, and raw debug events are not public fields.
      properties:
        enabled:
          type: boolean
          default: false
        network_event_count:
          type: integer
          minimum: 0
          default: 0
        console_message_count:
          type: integer
          minimum: 0
          default: 0
    PublicBrowserFailureDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public sanitized browser failure summary. It exposes only stable failure
        category, stage, attempt count, lease-acquired state, and an allowlisted
        error code. Raw URLs, proxy credentials, profile ids, identity ids, CDP
        URLs, provider payloads, and raw audit rows are not public fields.
      properties:
        present:
          type: boolean
          default: false
        category:
          type: string
          enum:
            - none
            - capacity
            - network_tunnel_failed
            - network_error
            - timeout
            - anti_bot_challenge
            - content_quality
            - budget_exhausted
            - render_error
            - other
          default: none
        stage:
          type: string
          enum:
            - none
            - capacity
            - browser_open
            - navigation
            - render
            - quality
            - unknown
          default: none
        attempt_count:
          type: integer
          minimum: 0
          default: 0
        browser_lease_acquired:
          type:
            - boolean
            - "null"
          default: null
        error_code:
          type:
            - string
            - "null"
          maxLength: 96
          default: null
    PublicPageDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public page diagnostics are sanitized aggregate fields for page-level
        extraction, browser debug, browser failure, and quality explainability.
        They do not expose raw selectors, raw debug events, profile data, proxy
        data, CDP URLs, DICloak/provider internals, or raw audit attempt rows.
      properties:
        adaptive_extraction:
          $ref: "#/components/schemas/PublicAdaptiveExtractionDiagnostics"
        browser_debug:
          $ref: "#/components/schemas/PublicBrowserDebugDiagnostics"
        browser_failure:
          $ref: "#/components/schemas/PublicBrowserFailureDiagnostics"
        content_quality:
          $ref: "#/components/schemas/PublicContentQualityDiagnostics"
    PublicCrawlRetryDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public sanitized aggregate for crawl retry taxonomy. Counts are bucketed
        into safe categories and do not expose queue row internals, retry policy
        reasons, identity feedback kinds, or audit attempts.
      properties:
        scheduled_count:
          type: integer
          minimum: 0
          default: 0
        failed_count:
          type: integer
          minimum: 0
          default: 0
        categories:
          type: object
          additionalProperties:
            type: integer
            minimum: 0
        next_retry_at:
          type:
            - string
            - "null"
          format: date-time
    PublicCrawlDiagnostics:
      type: object
      additionalProperties: false
      description: >
        Public crawl diagnostics are sanitized aggregate counters for processed
        pages, blocked pages, engine attempts, and retry taxonomy. They do not
        expose raw selectors, profile data, proxy data, CDP URLs,
        DICloak/provider internals, identity feedback kinds, retry policy
        reasons, or raw audit attempt rows.
      properties:
        processed_count:
          type: integer
          minimum: 0
          default: 0
        blocked_count:
          type: integer
          minimum: 0
          default: 0
        block_reasons:
          type: object
          additionalProperties:
            type: integer
            minimum: 0
        engine_attempts:
          type: object
          additionalProperties:
            type: integer
            minimum: 0
        retry:
          $ref: "#/components/schemas/PublicCrawlRetryDiagnostics"
    PublicUsage:
      type: object
      additionalProperties: false
      properties:
        cost_units:
          type:
            - integer
            - "null"
          minimum: 0
        budget_exhausted:
          type: boolean
    PublicCrawl:
      type: object
      additionalProperties: false
      required:
        - id
        - status
      properties:
        id:
          type: string
        run_id:
          type:
            - string
            - "null"
        status:
          $ref: "#/components/schemas/PublicStatus"
        submitted_url_count:
          type:
            - integer
            - "null"
          minimum: 0
        queued_url_count:
          type:
            - integer
            - "null"
          minimum: 0
        max_depth:
          type:
            - integer
            - "null"
          minimum: 0
        queue_counts:
          type: object
          additionalProperties:
            type: integer
        processed_count:
          type:
            - integer
            - "null"
          minimum: 0
        remaining_count:
          type:
            - integer
            - "null"
          minimum: 0
        stop_reason:
          type:
            - string
            - "null"
        diagnostics:
          $ref: "#/components/schemas/PublicCrawlDiagnostics"
        links:
          type: object
          additionalProperties:
            type: string
        results_url:
          type:
            - string
            - "null"
    GoogleMapsCoordinates:
      type: object
      additionalProperties: false
      properties:
        latitude:
          type:
            - number
            - "null"
        longitude:
          type:
            - number
            - "null"
    GoogleMapsSearchRequest:
      type: object
      additionalProperties: false
      required:
        - keyword
        - latitude
        - longitude
        - viewport_span
      properties:
        keyword:
          type: string
          minLength: 1
          maxLength: 256
          pattern: "^[^!]+$"
        latitude:
          type: number
          minimum: -90
          maximum: 90
        longitude:
          type: number
          minimum: -180
          maximum: 180
        viewport_span:
          type: number
          exclusiveMinimum: 0
          maximum: 100000000
        page_size:
          type: integer
          minimum: 1
          maximum: 20
          default: 20
        max_pages:
          type: integer
          minimum: 1
          maximum: 5
          default: 1
    GoogleMapsPlaceDetailsRequest:
      type: object
      additionalProperties: false
      required:
        - data_id
      properties:
        data_id:
          type: string
          description: Opaque Google Maps place identifier returned by search.
    GoogleMapsPlace:
      type: object
      additionalProperties: false
      required:
        - data_id
        - name
        - coordinates
      properties:
        rank:
          type:
            - integer
            - "null"
        data_id:
          type: string
        name:
          type: string
        category:
          type:
            - string
            - "null"
        address:
          type:
            - string
            - "null"
        coordinates:
          $ref: "#/components/schemas/GoogleMapsCoordinates"
        rating:
          type:
            - number
            - "null"
        domain:
          type:
            - string
            - "null"
        website:
          type:
            - string
            - "null"
        phone_display:
          type:
            - string
            - "null"
        phone_e164:
          type:
            - string
            - "null"
        telephone_uri:
          type:
            - string
            - "null"
    GoogleMapsPageProof:
      type: object
      additionalProperties: false
      required:
        - offset
        - status_code
        - response_bytes
        - result_count
        - overlap_with_earlier_pages
      properties:
        offset:
          type: integer
          minimum: 0
        status_code:
          type: integer
        response_bytes:
          type: integer
          minimum: 0
        result_count:
          type: integer
          minimum: 0
        overlap_with_earlier_pages:
          type: integer
          minimum: 0
    GoogleMapsSearchQuery:
      type: object
      additionalProperties: false
      required:
        - keyword
        - center
        - viewport_span
        - page_size
        - max_pages
      properties:
        keyword:
          type: string
        center:
          $ref: "#/components/schemas/GoogleMapsCoordinates"
        viewport_span:
          type: number
        page_size:
          type: integer
        max_pages:
          type: integer
    GoogleMapsSearchResponse:
      type: object
      additionalProperties: false
      required:
        - query
        - results
        - pages
        - termination
        - page_count
        - total_unique_results
      properties:
        query:
          $ref: "#/components/schemas/GoogleMapsSearchQuery"
        results:
          type: array
          items:
            $ref: "#/components/schemas/GoogleMapsPlace"
        pages:
          type: array
          items:
            $ref: "#/components/schemas/GoogleMapsPageProof"
        termination:
          type: string
          enum:
            - short_page
            - page_budget_exhausted
        page_count:
          type: integer
          minimum: 0
        total_unique_results:
          type: integer
          minimum: 0
    GoogleMapsPlaceDetailsResponse:
      type: object
      additionalProperties: false
      required:
        - data_id
        - name
      properties:
        data_id:
          type: string
        name:
          type: string
        address:
          type:
            - string
            - "null"
        domain:
          type:
            - string
            - "null"
        website:
          type:
            - string
            - "null"
        phone_display:
          type:
            - string
            - "null"
        phone_e164:
          type:
            - string
            - "null"
        telephone_uri:
          type:
            - string
            - "null"
    GoogleTrendsRelatedQueriesRequest:
      type: object
      additionalProperties: false
      required:
        - keyword
      properties:
        keyword:
          type: string
          minLength: 1
          maxLength: 200
        geo:
          type: string
          maxLength: 16
          default: ""
        timeframe:
          type: string
          minLength: 1
          maxLength: 64
          default: today 12-m
        category:
          type: integer
          minimum: 0
          default: 0
        property:
          type: string
          enum:
            - ""
            - images
            - news
            - youtube
            - froogle
          default: ""
        hl:
          type: string
          minLength: 2
          maxLength: 20
          default: en-US
        tz:
          type: integer
          minimum: -840
          maximum: 840
          default: 0
    GoogleTrendsRankedQuery:
      type: object
      additionalProperties: false
      required:
        - query
      properties:
        query:
          type: string
        value:
          type:
            - number
            - "null"
        formatted_value:
          type:
            - string
            - "null"
        link:
          type:
            - string
            - "null"
    GoogleTrendsRelatedQueriesResult:
      type: object
      additionalProperties: false
      required:
        - top
        - rising
        - cache_hit
      properties:
        top:
          type: array
          items:
            $ref: "#/components/schemas/GoogleTrendsRankedQuery"
        rising:
          type: array
          items:
            $ref: "#/components/schemas/GoogleTrendsRankedQuery"
        cache_hit:
          type: boolean
    GoogleTrendsJobError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - retryable
      properties:
        code:
          type: string
        message:
          type: string
        retryable:
          type: boolean
    GoogleTrendsJob:
      type: object
      additionalProperties: false
      required:
        - id
        - kind
        - status
        - request
        - attempt_count
        - max_attempts
      description: Public-safe job state. It never includes browser, profile, CDP, Cookie, reCAPTCHA, or widget-token fields.
      properties:
        id:
          type: string
        kind:
          type: string
          enum:
            - related_queries
        status:
          type: string
          enum:
            - queued
            - running
            - completed
            - failed
        request:
          $ref: "#/components/schemas/GoogleTrendsRelatedQueriesRequest"
        result:
          anyOf:
            - $ref: "#/components/schemas/GoogleTrendsRelatedQueriesResult"
            - type: "null"
        error:
          anyOf:
            - $ref: "#/components/schemas/GoogleTrendsJobError"
            - type: "null"
        attempt_count:
          type: integer
          minimum: 0
        max_attempts:
          type: integer
          minimum: 1
        created_at:
          type:
            - string
            - "null"
          format: date-time
        updated_at:
          type:
            - string
            - "null"
          format: date-time
        started_at:
          type:
            - string
            - "null"
          format: date-time
        finished_at:
          type:
            - string
            - "null"
          format: date-time
    GoogleTrendsJobResponse:
      type: object
      additionalProperties: false
      required:
        - job
      properties:
        job:
          $ref: "#/components/schemas/GoogleTrendsJob"
    PublicErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          $ref: "#/components/schemas/PublicError"
    PublicError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - type
        - retryable
      properties:
        code:
          type: string
          enum:
            - validation_error
            - invalid_request
            - unsupported_feature
            - authentication_required
            - permission_denied
            - not_found
            - run_not_found
            - crawl_not_found
            - artifact_not_found
            - session_not_found
            - profile_not_found
            - timeout
            - run_not_ready
            - artifact_expired
            - idempotency_conflict
            - idempotency_in_progress
            - quota_exceeded
            - rate_limited
            - fetch_failed
            - render_failed
            - maps_rate_limited
            - maps_challenge
            - maps_schema_changed
            - maps_invalid_response
            - maps_transport_failed
            - maps_page_budget_exhausted
            - google_trends_rate_limited
            - google_trends_challenge
            - google_trends_explore_failed
            - google_trends_widget_missing
            - google_trends_related_failed
            - google_trends_invalid_response
            - google_trends_transport_failed
            - google_trends_collection_failed
            - service_unavailable
            - internal_error
        message:
          type: string
        type:
          type: string
          enum:
            - auth
            - validation
            - quota
            - rate_limit
            - not_found
            - execution
            - conflict
            - internal
        retryable:
          type: boolean
        request_id:
          type:
            - string
            - "null"
        details:
          type: object
          additionalProperties: true
