{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/usestring-ai/json-schema/usestring-ai-fetch-request-schema.json",
  "title": "FetchRequest",
  "description": "Request body for POST /fetch. Unknown fields are rejected with a 400; `url` is the only required field. Field rules: `body` is forbidden on GET and HEAD. `jsonSchema` requires `format: json`. `headers` cannot be combined with `executeJS` or `requireWSS`. `captureXHR` requires `executeJS: true` and cannot be combined with `jsonSchema`; without `actions` or `screenshot` it also requires `format: json`. `screenshot` and `actions` are mutually exclusive; with either, `format: raw`, a non-GET `method`, `body`, `headers` and `solveCaptcha: false` are not supported. `jsonSchema` works with `actions` unless the request also takes a screenshot.",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/usestring-ai-openapi.json#/components/schemas/FetchRequest",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "url"
  ],
  "properties": {
    "url": {
      "type": "string",
      "format": "uri",
      "description": "The http or https URL to fetch."
    },
    "method": {
      "type": "string",
      "enum": [
        "GET",
        "POST",
        "PUT",
        "PATCH",
        "DELETE",
        "HEAD",
        "OPTIONS"
      ],
      "default": "GET",
      "description": "HTTP method. Accepted in any case (`get` and `Post` work). Any other method returns a 400. A non-GET method or a `body` is sent only on fetch paths that deliver it exactly; if none can, the request returns a 400 before anything is sent. A write (POST, PUT, PATCH, DELETE) reaches the destination at most once, so an error on a write does not prove the destination did not act on it."
    },
    "body": {
      "type": [
        "string",
        "object"
      ],
      "description": "Request body to send to the destination. Forbidden on GET and HEAD. A string is sent as given; an object is sent as the exact JSON text you wrote."
    },
    "format": {
      "type": "string",
      "enum": [
        "json",
        "raw",
        "markdown"
      ],
      "default": "json",
      "description": "Response format. `json`: an envelope with the destination's status, headers, parsed body and final URL. `raw`: the original bytes, gzip-compressed, with the destination status in `x-status-code`. `markdown`: HTML converted to Markdown (`text/markdown`). See https://portal.usestring.ai/docs/fetch/response-formats"
    },
    "markdownMode": {
      "type": "string",
      "enum": [
        "readable",
        "full"
      ],
      "default": "full",
      "description": "Markdown preservation level. `full` converts the whole cleaned page, navigation and footers included; `readable` removes boilerplate for a smaller output. Ignored unless `format` is `markdown`."
    },
    "mainContentOnly": {
      "type": "boolean",
      "default": false,
      "description": "Remove page chrome before conversion. Ignored unless `format` is `markdown`."
    },
    "jsonSchema": {
      "type": "object",
      "description": "A JSON Schema to extract into with AI. On success the response body is the extracted object itself. Must be a valid JSON Schema object (shorthand such as `{\"title\": \"string\"}` is a 400). Requires `format: json`. Limits: nesting depth 10, 200 keys, 50 KB serialized. Adds a dynamic extraction fee. See https://portal.usestring.ai/docs/fetch/structured-extraction"
    },
    "executeJS": {
      "type": "boolean",
      "description": "Render the page in a browser. Incompatible with `headers`. See https://portal.usestring.ai/docs/fetch/javascript-rendering"
    },
    "requireWSS": {
      "type": "boolean",
      "description": "Require a browser WebSocket fetch path. Incompatible with `headers`."
    },
    "captureXHR": {
      "description": "Return the XHR and fetch() requests the page makes, as `xhr`. `true` (or `{}`) captures all of them; `{ \"include\": [...] }` captures only those that match a filter. Requires `executeJS: true`. See https://portal.usestring.ai/docs/fetch/xhr-capture",
      "oneOf": [
        {
          "type": "boolean"
        },
        {
          "$ref": "#/$defs/CaptureXhrOptions"
        }
      ]
    },
    "headers": {
      "type": "object",
      "description": "Custom HTTP headers to forward (max 50). Direct (request-based) fetch only. Names are case-insensitive and may not repeat in a different case. Values may not contain control characters such as CR, LF or NUL, or characters above U+00FF. Service-managed headers cannot be set: proxy-authorization, proxy-authenticate, proxy-connection, connection, transfer-encoding, content-length, te, upgrade, keep-alive, trailer, host. See https://portal.usestring.ai/docs/fetch/custom-headers",
      "maxProperties": 50,
      "propertyNames": {
        "minLength": 1,
        "maxLength": 256,
        "pattern": "^[A-Za-z0-9!#$%&'*+.^_`|~-]+$"
      },
      "additionalProperties": {
        "type": "string",
        "maxLength": 32768
      }
    },
    "countryCode": {
      "type": "string",
      "minLength": 2,
      "maxLength": 2,
      "description": "ISO 3166-1 alpha-2 country for the proxy exit. See https://portal.usestring.ai/docs/fetch/proxies-and-geolocation"
    },
    "solveCaptcha": {
      "type": "boolean",
      "default": true,
      "description": "Solve captcha challenges. `false` fails on a challenge instead. See https://portal.usestring.ai/docs/fetch/captcha-solving"
    },
    "ignoreCertificateErrors": {
      "type": "boolean",
      "default": true,
      "description": "Skip TLS certificate verification (the default). Send `false` to require a valid certificate; a bad certificate then fails with `TargetCertificateError`. Send `false` for credentials, payments, or data you will treat as authoritative."
    },
    "screenshot": {
      "type": "boolean",
      "description": "Capture a screenshot, returned as base64 in the JSON body. Shorthand for one `screenshot` action. Mutually exclusive with `actions`. Billed as a browser session. See https://portal.usestring.ai/docs/screenshots/overview"
    },
    "actions": {
      "type": "array",
      "minItems": 1,
      "maxItems": 50,
      "items": {
        "$ref": "#/$defs/BrowserAction"
      },
      "description": "Browser actions to run, in order, after the API loads `url` (1 to 50). Mutually exclusive with `screenshot`. Billed as a browser session. See https://portal.usestring.ai/docs/screenshots/browser-actions"
    }
  },
  "$defs": {
    "BrowserAction": {
      "type": "object",
      "description": "One browser action. Each action has a `type` and fields of its own; this schema checks only `type`. Fields by type: `navigate`: `url`. `click`: `selector`, optional `all` (true clicks every match). `write`: `text` (types into the focused element). `press`: `key` (for example `Enter`, `Tab`). `hover`: `selector`. `scroll`: optional `direction` (`up`/`down`/`left`/`right`), `amount`, `selector`. `selectOption`: `selector`, `value` (string or array of strings). `wait`: optional `milliseconds` (max 30000), `selector`, `timeout` (max 30000). `screenshot`: optional `full_page`, `quality` (1-100); at most one per request. `waitForResponse`: `url` (required), optional `match` (`contains`/`glob`/`regex`, default `contains`), `methods`, `statusCodes`, `timeout` (0-30000, default 30000), `onTimeout` (`fail`/`continue`, default `fail`), `asResult` (default false; at most one action may set it). The whole sequence must finish within 180 seconds. See https://portal.usestring.ai/docs/screenshots/browser-actions and https://portal.usestring.ai/docs/fetch/xhr-capture#wait-for-a-response",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "navigate",
            "click",
            "write",
            "press",
            "hover",
            "scroll",
            "selectOption",
            "wait",
            "screenshot",
            "waitForResponse"
          ],
          "description": "The action to run."
        }
      }
    },
    "CaptureXhrOptions": {
      "type": "object",
      "description": "`{}` captures every XHR and fetch() request; `{ \"include\": [...] }` captures only requests that match at least one filter.",
      "properties": {
        "include": {
          "type": "array",
          "minItems": 1,
          "maxItems": 10,
          "items": {
            "$ref": "#/$defs/XhrFilter"
          },
          "description": "1 to 10 filters."
        }
      }
    },
    "XhrFilter": {
      "type": "object",
      "description": "A `captureXHR.include` filter. A request matches when it meets every condition the filter sets. See https://portal.usestring.ai/docs/fetch/xhr-capture#filter-with-include",
      "additionalProperties": false,
      "required": [
        "url"
      ],
      "properties": {
        "url": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2048,
          "description": "Pattern matched against the full request URL with its query string."
        },
        "match": {
          "type": "string",
          "enum": [
            "contains",
            "glob",
            "regex"
          ],
          "default": "contains",
          "description": "How `url` is matched: `contains` is a case-sensitive substring; `glob` matches the whole URL (`*` any run, `?` one character); `regex` is an RE2 expression that may match anywhere."
        },
        "methods": {
          "type": "array",
          "description": "Match only these methods. Any case is accepted. Default: any method.",
          "items": {
            "type": "string",
            "enum": [
              "GET",
              "POST",
              "PUT",
              "PATCH",
              "DELETE",
              "HEAD",
              "OPTIONS"
            ]
          }
        },
        "statusCodes": {
          "type": "array",
          "minItems": 1,
          "maxItems": 20,
          "description": "Match only responses with one of these statuses. A failed request, or one with no response yet, never matches. Default: any status.",
          "items": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          }
        }
      }
    }
  }
}