---
title: "Fetch a URL"
method: POST
path: "/fetch"
tags: ["Fetch"]
---

# Fetch a URL

`POST /fetch`

## Request

- Base URL: `https://request.usestring.ai/v1`
- URL: `https://request.usestring.ai/v1/fetch`
- Auth: HTTP bearer

Fetch one http or https URL and return the destination's response as a JSON envelope, Markdown, or raw bytes. String picks the fetch strategy (direct request or browser, proxy class, captcha solving) automatically. Use it to read a known URL, render JavaScript, run browser actions or take a screenshot, capture a page's XHR calls, or extract fields with a JSON Schema; use searchWeb when you have a query instead of a URL.

## Request body

- FetchRequest: 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.
  - `url` string, uri, required: The http or https URL to fetch.
  - `method` 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS': 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` union: 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.
    - string
    - object
  - `format` 'json' | 'raw' | 'markdown': 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` 'readable' | 'full': 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` boolean: Remove page chrome before conversion. Ignored unless `format` is `markdown`.
  - `jsonSchema` object: 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` boolean: Render the page in a browser. Incompatible with `headers`. See https://portal.usestring.ai/docs/fetch/javascript-rendering
  - `requireWSS` boolean: Require a browser WebSocket fetch path. Incompatible with `headers`.
  - `captureXHR` union: 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
    - boolean
    - CaptureXhrOptions: `{}` captures every XHR and fetch() request; `{ "include": [...] }` captures only requests that match at least one filter.
      - `include` XhrFilter[]: 1 to 10 filters.
        - `url` string, required: Pattern matched against the full request URL with its query string.
        - `match` 'contains' | 'glob' | 'regex': 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` string[]: Match only these methods. Any case is accepted. Default: any method.
        - `statusCodes` integer[]: Match only responses with one of these statuses. A failed request, or one with no response yet, never matches. Default: any status.
  - `headers` object: 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
  - `countryCode` string: ISO 3166-1 alpha-2 country for the proxy exit. See https://portal.usestring.ai/docs/fetch/proxies-and-geolocation
  - `solveCaptcha` boolean: Solve captcha challenges. `false` fails on a challenge instead. See https://portal.usestring.ai/docs/fetch/captcha-solving
  - `ignoreCertificateErrors` boolean: 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` boolean: 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` BrowserAction[]: 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
    - `type` 'navigate' | 'click' | 'write' | 'press' | 'hover' | 'scroll' | 'selectOption' | 'wait' | 'screenshot' | 'waitForResponse', required: The action to run.

## Response `200`

Successful fetch. The body shape depends on `format`, `jsonSchema`, `screenshot` and `actions`. The destination's own status is in the JSON `statusCode` or the `x-status-code` header; a destination 304 is still an HTTP 200 here.

- union
  - FetchResponse: 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`.
    - `statusCode` integer: The destination's HTTP status code.
    - `headers` object: The destination's response headers, filtered. Values can be arrays of strings.
    - `data` unknown
    - `finalUrl` string: 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` object: Present only if a screenshot was taken.
      - `format` string: Image format, for example `png`.
      - `base64` string: The image, base64-encoded.
    - `matchedResponse` object: Present only when the action sequence succeeded and its `asResult` action matched. Describes the response now in `data`.
      - `url` string
      - `method` string
      - `statusCode` integer
      - `headers` object
      - `bodyEncoding` 'utf8' | 'base64': When `base64`, decode `data` first.
    - `xhr` XhrEntry[]: Present only with `captureXHR`: the captured requests, in the order the page sent them. Empty when nothing qualified.
      - `resourceType` 'xhr' | 'fetch': Whether the page used XMLHttpRequest or fetch().
      - `request` object
        - `url` string: The full request URL, query string included.
        - `method` string: The request method, such as GET or POST.
        - `headers` object: The request headers, each value a single string.
        - `body` string: The body the page sent, encoded as `bodyEncoding` says. Absent when there was no body or it was omitted.
        - `bodyEncoding` 'utf8' | 'base64': `utf8` for valid UTF-8 text, `base64` for anything else.
        - `bodyOmitted` 'too_large' | 'budget_exhausted' | 'unavailable': Why `body` is absent.
      - `response` object: Absent when no response arrived.
        - `statusCode` number: The response status.
        - `headers` object: The response headers, each value a single string.
        - `body` string: The response body, decoded from any content-encoding and encoded as `bodyEncoding` says.
        - `bodyEncoding` 'utf8' | 'base64': `utf8` for valid UTF-8 text, `base64` for anything else.
        - `bodyOmitted` 'too_large' | 'budget_exhausted' | 'unavailable': Why `body` is absent.
      - `error` string: The network error, when the request failed.
      - `matchedFilter` number: With `captureXHR.include`: the 0-based index of the first filter this request matched.
      - `timing` object
        - `startedAt` number: When the page sent the request, in milliseconds since the Unix epoch.
        - `durationMs` number: Milliseconds until the response finished loading or the request failed. Absent while in flight.
    - `xhrTruncated` boolean: `true` when a capture limit left requests or bodies out of `xhr`. Absent otherwise.
    - `error` string: Present if the browser action sequence failed (the response is still HTTP 200), for example `Browser action sequence failed`.
    - `failedActionIndex` integer: 0-based index into `actions` of the action that failed.
    - `extracted` boolean: `false` on a `jsonSchema` fallback: extraction did not satisfy the schema and `data` holds the unextracted page.
    - `reason` 'schema_mismatch' | 'unparseable_output' | 'llm_error' | 'body_too_large' | 'empty_body': `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.
  - unknown

## Other responses

- `400`: Validation error: bad input, or a method that requires KYC for that path (`issues[].field` is `url`). Also returned when no fetch path can send the requested method or body.
- `401`: Missing or invalid Authorization header.
- `402`: The key is valid but the account balance can't cover the request.
- `403`: Either the destination domain is not enabled for your organization (body has `reason`), or the destination's own 403 passed through as a terminal origin failure (`errorType: TerminalOriginError`, body has `data`).
- `429`: Rate limit exceeded. The default limit is 60 requests per second per organization, averaged over a rolling window. Back off and retry with exponential backoff and jitter.
- `500`: Internal server error.
- `502`: Upstream or destination error: the destination answered with an error, could not be reached, or the request could not be completed. Read `statusCode` (the destination's status, if any) and `errorType`.
- `503`: XHR capture or `waitForResponse` is at capacity or temporarily unavailable. Retry, after `Retry-After` seconds when that header is present.
- `504`: The destination did not respond in time (`errorType: TargetTimeoutError`). Retry later.
- `default`: Terminal origin failure (`errorType: TerminalOriginError`): returned under the destination's own HTTP status (for example 403 or 530), with the destination's body in `data` and its headers in `headers`. Do not retry.

---

[API](https://skmtc.dev/usestring/apis/string-web-access-api.md) · [All operations](https://skmtc.dev/usestring/apis/string-web-access-api/llms.txt) · [OpenAPI document](https://skmtc.dev/usestring/apis/string-web-access-api/revisions/fd336960036e?raw)
