{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/usestring-ai/json-schema/usestring-ai-fetch-response-schema.json",
  "title": "Fetch JSON envelope",
  "description": "The `format: json` response body. Also the envelope for `screenshot`/`actions` requests (whatever `format`), and the `jsonSchema` fallback envelope (`extracted: false`). A destination `304 Not Modified` is still an HTTP 200 here, with `statusCode: 304`.",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/usestring-ai-openapi.json#/components/schemas/FetchResponse",
  "type": "object",
  "properties": {
    "statusCode": {
      "type": "integer",
      "description": "The destination's HTTP status code."
    },
    "headers": {
      "type": "object",
      "description": "The destination's response headers, filtered. Values can be arrays of strings.",
      "additionalProperties": {
        "type": [
          "string",
          "array"
        ],
        "items": {
          "type": "string"
        }
      }
    },
    "data": {
      "description": "The response body. Parsed JSON when the destination returned JSON, otherwise text. With `screenshot`/`actions`: the final page as HTML, or Markdown with `format: markdown`; when the sequence succeeded and a `waitForResponse` action with `asResult` matched, the matched response's body as a string instead."
    },
    "finalUrl": {
      "type": "string",
      "description": "The URL the response was served from after any redirects (or after all actions ran), or the requested URL if there was no redirect."
    },
    "screenshot": {
      "type": "object",
      "description": "Present only if a screenshot was taken.",
      "properties": {
        "format": {
          "type": "string",
          "description": "Image format, for example `png`."
        },
        "base64": {
          "type": "string",
          "description": "The image, base64-encoded."
        }
      }
    },
    "matchedResponse": {
      "type": "object",
      "description": "Present only when the action sequence succeeded and its `asResult` action matched. Describes the response now in `data`.",
      "properties": {
        "url": {
          "type": "string"
        },
        "method": {
          "type": "string"
        },
        "statusCode": {
          "type": "integer"
        },
        "headers": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "bodyEncoding": {
          "type": "string",
          "enum": [
            "utf8",
            "base64"
          ],
          "description": "When `base64`, decode `data` first."
        }
      }
    },
    "xhr": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/XhrEntry"
      },
      "description": "Present only with `captureXHR`: the captured requests, in the order the page sent them. Empty when nothing qualified."
    },
    "xhrTruncated": {
      "type": "boolean",
      "description": "`true` when a capture limit left requests or bodies out of `xhr`. Absent otherwise."
    },
    "error": {
      "type": "string",
      "description": "Present if the browser action sequence failed (the response is still HTTP 200), for example `Browser action sequence failed`."
    },
    "failedActionIndex": {
      "type": "integer",
      "description": "0-based index into `actions` of the action that failed."
    },
    "extracted": {
      "type": "boolean",
      "description": "`false` on a `jsonSchema` fallback: extraction did not satisfy the schema and `data` holds the unextracted page."
    },
    "reason": {
      "type": "string",
      "enum": [
        "schema_mismatch",
        "unparseable_output",
        "llm_error",
        "body_too_large",
        "empty_body"
      ],
      "description": "`jsonSchema` fallback reason. `schema_mismatch`: a required field was not found; retrying will not help. `unparseable_output` and `llm_error`: usually transient, worth a retry. `body_too_large`: extraction skipped. `empty_body`: nothing to extract."
    }
  },
  "$defs": {
    "XhrEntry": {
      "type": "object",
      "description": "One captured XHR or fetch() request. See https://portal.usestring.ai/docs/fetch/xhr-capture#the-xhr-entry",
      "properties": {
        "resourceType": {
          "type": "string",
          "enum": [
            "xhr",
            "fetch"
          ],
          "description": "Whether the page used XMLHttpRequest or fetch()."
        },
        "request": {
          "type": "object",
          "properties": {
            "url": {
              "type": "string",
              "description": "The full request URL, query string included."
            },
            "method": {
              "type": "string",
              "description": "The request method, such as GET or POST."
            },
            "headers": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "description": "The request headers, each value a single string."
            },
            "body": {
              "type": "string",
              "description": "The body the page sent, encoded as `bodyEncoding` says. Absent when there was no body or it was omitted."
            },
            "bodyEncoding": {
              "type": "string",
              "enum": [
                "utf8",
                "base64"
              ],
              "description": "`utf8` for valid UTF-8 text, `base64` for anything else."
            },
            "bodyOmitted": {
              "type": "string",
              "enum": [
                "too_large",
                "budget_exhausted",
                "unavailable"
              ],
              "description": "Why `body` is absent."
            }
          }
        },
        "response": {
          "type": "object",
          "description": "Absent when no response arrived.",
          "properties": {
            "statusCode": {
              "type": "number",
              "description": "The response status."
            },
            "headers": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "description": "The response headers, each value a single string."
            },
            "body": {
              "type": "string",
              "description": "The response body, decoded from any content-encoding and encoded as `bodyEncoding` says."
            },
            "bodyEncoding": {
              "type": "string",
              "enum": [
                "utf8",
                "base64"
              ],
              "description": "`utf8` for valid UTF-8 text, `base64` for anything else."
            },
            "bodyOmitted": {
              "type": "string",
              "enum": [
                "too_large",
                "budget_exhausted",
                "unavailable"
              ],
              "description": "Why `body` is absent."
            }
          }
        },
        "error": {
          "type": "string",
          "description": "The network error, when the request failed."
        },
        "matchedFilter": {
          "type": "number",
          "description": "With `captureXHR.include`: the 0-based index of the first filter this request matched."
        },
        "timing": {
          "type": "object",
          "properties": {
            "startedAt": {
              "type": "number",
              "description": "When the page sent the request, in milliseconds since the Unix epoch."
            },
            "durationMs": {
              "type": "number",
              "description": "Milliseconds until the response finished loading or the request failed. Absent while in flight."
            }
          }
        }
      }
    }
  }
}