{
  "openapi": "3.1.0",
  "info": {
    "title": "Zenrows API",
    "version": "1.0.0",
    "summary": "Reach any page, including the protected web, and return it as HTML, Markdown, plaintext, PDF or structured JSON.",
    "description": "Zenrows is web data infrastructure for agents and applications. Three HTTP surfaces are described here:\n\n- **Fetch and Extract**: one synchronous request per page, at `https://api.zenrows.com/v1/`. Authentication is the `apikey` query parameter.\n- **Crawl**: collect the URLs behind one start page, at `https://api.zenrows.com/v1/crawls`. Authentication is the `X-API-Key` header or the `apikey` query parameter.\n- **Batch**: asynchronous jobs of up to 100,000 URLs, at `https://async.api.zenrows.com/v1`. Authentication is the `X-API-Key` header.\n\n**Browser** is not described here because it is not HTTP: you connect Puppeteer or Playwright to a WebSocket endpoint. See https://docs.zenrows.com/browser-sessions/introduction.\n\n**Cost.** A request costs 1 credit, 5 with JavaScript rendering, 10 with premium proxies, 25 with both, and 1 to 25 under `mode=auto`. Failed requests are never charged. The free tier is 5,000 credits a month, no card.\n\n**Versioning and deprecation.** The version is in the URL path (`/v1`, the only version so far). Inside a version Zenrows only adds: new endpoints, optional parameters, response fields and headers. Nothing is removed or changed. Retiring a version is announced at least twelve months ahead, and every response from a deprecated version carries the `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers. Policy: https://docs.zenrows.com/api-versioning.\n\n**Getting a key without a human.** `POST https://app.zenrows.com/api/agent/signup` returns a usable key; the spec is at https://www.zenrows.com/auth.md and a setup playbook at https://www.zenrows.com/SKILL.md.",
    "termsOfService": "https://www.zenrows.com/legal/terms-of-use",
    "contact": {
      "name": "Zenrows support",
      "email": "support@zenrows.com",
      "url": "https://www.zenrows.com/contact"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://www.zenrows.com/legal/terms-of-use"
    }
  },
  "externalDocs": {
    "description": "Zenrows documentation",
    "url": "https://docs.zenrows.com"
  },
  "servers": [
    {
      "url": "https://api.zenrows.com/v1",
      "description": "Fetch and Extract (synchronous)"
    }
  ],
  "tags": [
    {
      "name": "Fetch",
      "description": "Retrieve one page, optionally rendered, proxied, converted or extracted."
    },
    {
      "name": "Extract",
      "description": "Which domains Extract serves, and getting a new one prepared."
    },
    {
      "name": "Crawl",
      "description": "Collect the URLs behind one start page, and each page's HTML when asked."
    },
    {
      "name": "Batch",
      "description": "Submit many URLs as one job and collect the results."
    },
    {
      "name": "Account",
      "description": "Plan, credits and concurrency for the calling key."
    },
    {
      "name": "Onboarding",
      "description": "Get a working key with no human in the loop."
    }
  ],
  "security": [
    {
      "apiKeyQuery": []
    }
  ],
  "paths": {
    "/": {
      "parameters": [
        {
          "name": "url",
          "in": "query",
          "description": "The URL of the page to retrieve.",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uri",
            "examples": [
              "https://www.scrapingcourse.com/ecommerce/"
            ]
          },
          "example": "https://www.scrapingcourse.com/ecommerce/"
        },
        {
          "name": "mode",
          "in": "query",
          "description": "Adaptive Stealth Mode. `auto` starts from the cheapest viable configuration and escalates to JavaScript rendering or premium proxies only when the target requires it. You are billed for the configuration that succeeds.",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "auto"
            ]
          }
        },
        {
          "name": "js_render",
          "in": "query",
          "description": "Render the page in a headless browser before returning it. Required for content that only exists after JavaScript runs.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "js_instructions",
          "in": "query",
          "description": "JSON array of browser instructions (click, fill, scroll, wait) executed on the page before the content is returned. Requires js_render.",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "custom_headers",
          "in": "query",
          "description": "Forward your own request headers (cookies, referer) to the target.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "premium_proxy",
          "in": "query",
          "description": "Route the request through residential IPs. Required by most protected sites.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "proxy_country",
          "in": "query",
          "description": "Two-letter country code for the exit IP. Requires premium_proxy.",
          "required": false,
          "schema": {
            "type": "string",
            "pattern": "^[a-z]{2}$",
            "examples": [
              "us"
            ]
          },
          "example": "us"
        },
        {
          "name": "session_id",
          "in": "query",
          "description": "Reuse the same IP across requests for up to 10 minutes. Any integer you choose identifies the session.",
          "required": false,
          "schema": {
            "type": "integer"
          }
        },
        {
          "name": "original_status",
          "in": "query",
          "description": "Return the target's own HTTP status code instead of the Zenrows one.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "allowed_status_codes",
          "in": "query",
          "description": "Comma-separated status codes whose body should be returned instead of raising an error, for example `404,500`.",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "wait_for",
          "in": "query",
          "description": "CSS selector to wait for before returning. Requires js_render.",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "wait",
          "in": "query",
          "description": "Milliseconds to wait after load before returning. Requires js_render.",
          "required": false,
          "schema": {
            "type": "integer",
            "default": 0,
            "minimum": 0
          }
        },
        {
          "name": "block_resources",
          "in": "query",
          "description": "Comma-separated resource types to block (for example `image,media,font`). Blocking is on by default.",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "json_response",
          "in": "query",
          "description": "Return a JSON envelope that also carries the network requests (XHR/fetch) the page made.",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "css_extractor",
          "in": "query",
          "description": "JSON object mapping output keys to CSS selectors, applied to the retrieved page.",
          "required": false,
          "schema": {
            "type": "string",
            "examples": [
              "{\"title\":\"h1\",\"price\":\".price\"}"
            ]
          },
          "example": "{\"title\":\"h1\",\"price\":\".price\"}"
        },
        {
          "name": "extract",
          "in": "query",
          "description": "Return structured JSON extracted from the page with no selectors to write (Extract). Omit it and Extract is off. `auto` and `native` return the website's own field names; `standard` returns a canonical schema shared by every website in a vertical (real estate only for now). Extract works on any prepared domain, with any active API key (prepare a new one with `POST /extract/prepared-domains`), and is currently free on top of the Fetch cost. A domain, or a page type on it, that is not prepared yet answers 403 `REQS007`: see `requestExtractDomain`.",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "auto",
              "native",
              "standard"
            ]
          }
        },
        {
          "name": "extract_fields",
          "in": "query",
          "description": "Comma-separated list of the fields `extract` should return, dot-notated for fields inside a group (for example `products.name,products.price`). Omit it to receive every field.",
          "required": false,
          "schema": {
            "type": "string",
            "examples": [
              "products.name,products.price"
            ]
          },
          "example": "products.name,products.price"
        },
        {
          "name": "autoparse",
          "in": "query",
          "description": "Deprecated in favour of Extract (`extract=auto`). Returns general-purpose JSON parsed from the page, not tailored to the website.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          },
          "deprecated": true
        },
        {
          "name": "response_type",
          "in": "query",
          "description": "Convert the page before returning it: Markdown, plaintext or PDF.",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "markdown",
              "plaintext",
              "pdf"
            ]
          }
        },
        {
          "name": "screenshot",
          "in": "query",
          "description": "Return an above-the-fold screenshot of the page. Requires js_render.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "screenshot_fullpage",
          "in": "query",
          "description": "Return a full-page screenshot. Requires js_render.",
          "required": false,
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "screenshot_selector",
          "in": "query",
          "description": "Screenshot only the element matching this CSS selector. Requires js_render.",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "screenshot_format",
          "in": "query",
          "description": "Screenshot image format.",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "png",
              "jpeg"
            ],
            "default": "png"
          }
        },
        {
          "name": "screenshot_quality",
          "in": "query",
          "description": "JPEG quality, 1 to 100. Only with screenshot_format=jpeg.",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        {
          "name": "outputs",
          "in": "query",
          "description": "Comma-separated data types to pull out of the retrieved HTML (for example `emails,phone_numbers`).",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "fetchPage",
        "summary": "Fetch a page",
        "description": "Retrieve a URL through Zenrows and return its content. The same operation covers Extract (`extract=auto` or `css_extractor`), format conversion (`response_type`), screenshots and structured output, because they are configurations of one request rather than separate endpoints.",
        "tags": [
          "Fetch"
        ],
        "responses": {
          "200": {
            "description": "The target's content, in the shape the request asked for: HTML by default, Markdown or plaintext with `response_type`, a PDF or PNG/JPEG binary for `response_type=pdf` and the screenshot parameters, and JSON for `extract`, `css_extractor`, `autoparse` or `json_response`.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "The page as returned by the target."
                },
                "example": "<!doctype html>\n<html lang=\"en-US\">\n<head>\n<title>Ecommerce Test Site to Learn Web Scraping</title>\n</head>\n<body>\n<h1>Shop</h1>\n...\n</body>\n</html>"
              },
              "text/markdown": {
                "schema": {
                  "type": "string",
                  "description": "The page converted to Markdown."
                },
                "example": "[Ecommerce Test Site to Learn Web Scraping](https://www.scrapingcourse.com/ecommerce/)\n\n# Shop\n\n- [Abominable Hoodie](https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/) $69.00\n..."
              },
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "The page as plaintext."
                },
                "example": "Ecommerce Test Site to Learn Web Scraping\nShop\nAbominable Hoodie $69.00\n..."
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Structured output: the extracted fields, the autoparsed record, or the JSON envelope with captured network requests.",
                  "additionalProperties": true
                },
                "example": {
                  "html": "<!doctype html>\n<html lang=\"en-US\">...</html>",
                  "parsed": {
                    "breadcrumbs": [
                      {
                        "name": "Home",
                        "position": 1,
                        "url": "https://www.scrapingcourse.com/ecommerce"
                      }
                    ],
                    "product": {
                      "name": "Abominable Hoodie",
                      "availability": "out_of_stock",
                      "category": "Hoodies & Sweatshirts"
                    }
                  }
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "The page rendered to PDF."
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "Screenshot of the page or of the selected element."
                }
              }
            },
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "400": {
            "description": "The request is malformed, or a parameter combination is not allowed.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "REQS004",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Invalid value provided for 'js_render' parameter; invalid boolean value 'maybe' (REQS004)",
                  "type": "https://docs.zenrows.com/api-error-codes#REQS004"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "403": {
            "description": "With `extract=auto`, error `REQS007`: the domain, or this page type on it, has not been prepared for Extract yet. The message names the domain. The request is not charged and no HTML is returned. Prepare the domain with `requestExtractDomain`, then retry once it reports `ready`. Documented at https://docs.zenrows.com/api-error-codes#REQS007.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "REQS007",
                  "detail": "Extract has not been prepared for example.org yet. Ask for it with POST /v1/extract/prepared-domains, then retry once it reports ready. GET /v1/extract/domains lists what Extract serves today.",
                  "instance": "/v1",
                  "status": 403,
                  "title": "Extract is not prepared for the requested domain (example.org) (REQS007)",
                  "type": "https://docs.zenrows.com/api-error-codes#REQS007"
                }
              }
            }
          },
          "422": {
            "description": "Zenrows reached the target but could not return it under the requested configuration. With `extract`, the lowercase code `no_data_extracted` means something else: Extract knows this page type and applied its extraction, but no field came back filled. That answer is not charged, carries no HTML, and comes back the same on a retry, so do not retry it; check that the page rendered fully instead. The lowercase code `blocked_document` means the page Zenrows fetched was a bot challenge, an error page or a page that had not finished loading, so Extract had nothing real to read. It is not charged either; retry with `js_render=true` and/or `premium_proxy=true`, or with Adaptive Stealth Mode (`mode=auto`). Documented at https://docs.zenrows.com/api-error-codes#no_data_extracted.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "RESP001",
                  "detail": "The target could not be returned under this configuration. Try js_render=true and premium_proxy=true, or mode=auto.",
                  "instance": "/v1",
                  "status": 422,
                  "title": "Could not get content (RESP001)",
                  "type": "https://docs.zenrows.com/api-error-codes#RESP001"
                }
              }
            }
          },
          "429": {
            "description": "Error `AUTH008`: every concurrency slot on the plan is occupied. There is no fixed requests-per-minute quota to wait out and no Retry-After to read: a slot frees when one of your requests in flight finishes. Read `Concurrency-Remaining` on any response to pace yourself, and back off exponentially before retrying. Documented at https://docs.zenrows.com/api-error-codes#AUTH008 and https://docs.zenrows.com/fetch/features/concurrency.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH008",
                  "detail": "Every concurrency slot on the plan is in use. Retry when a request in flight finishes.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Concurrency limit reached (AUTH008)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH008"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl --max-time 180 \"https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fget&mode=auto\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "# pip install requests\nimport requests\n\nurl = 'https://httpbin.io/get'\napikey = 'YOUR_ZENROWS_API_KEY'\nparams = {\n    'url': url,\n    'apikey': apikey,\n    'mode': 'auto',\n}\n\nresponse = requests.get('https://api.zenrows.com/v1/', params=params)\nprint(response.text)"
          },
          {
            "lang": "javascript",
            "label": "Node.js",
            "source": "// npm install axios\nconst axios = require('axios');\n\nconst url = 'https://httpbin.io/get';\nconst apikey = 'YOUR_ZENROWS_API_KEY';\naxios({\n    url: 'https://api.zenrows.com/v1/',\n    method: 'GET',\n    params: {\n        'url': url,\n        'apikey': apikey,\n        'mode': 'auto',\n    },\n})\n    .then(response => console.log(response.data))\n    .catch(error => console.log(error));"
          },
          {
            "lang": "go",
            "label": "Go",
            "source": "package main\n\nimport (\n    \"io\"\n    \"log\"\n    \"net/http\"\n)\n\nfunc main() {\n    client := &http.Client{}\n    req, err := http.NewRequest(\"GET\", \"https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fget&mode=auto\", nil)\n    if err != nil {\n        log.Fatalln(err)\n    }\n    resp, err := client.Do(req)\n    if err != nil {\n        log.Fatalln(err)\n    }\n    defer resp.Body.Close()\n\n    body, err := io.ReadAll(resp.Body)\n    if err != nil {\n        log.Fatalln(err)\n    }\n\n    log.Println(string(body))\n}"
          },
          {
            "lang": "php",
            "label": "PHP",
            "source": "<?php\n$ch = curl_init();\ncurl_setopt($ch, CURLOPT_URL, 'https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fget&mode=auto');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\ncurl_setopt($ch, CURLOPT_TIMEOUT, 180);\n$response = curl_exec($ch);\necho $response . PHP_EOL;\ncurl_close($ch);\n?>"
          },
          {
            "lang": "ruby",
            "label": "Ruby",
            "source": "# gem install faraday\nrequire 'faraday'\n\nurl = URI.parse('https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fget&mode=auto')\nconn = Faraday.new()\nconn.options.timeout = 180\nres = conn.get(url, nil, nil)\nprint(res.body)"
          },
          {
            "lang": "java",
            "label": "Java",
            "source": "import org.apache.hc.client5.http.fluent.Request;\n\npublic class APIRequest {\n    public static void main(final String... args) throws Exception {\n        String apiUrl = \"https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fget&mode=auto\";\n        String response = Request.get(apiUrl)\n                .execute().returnContent().asString();\n\n        System.out.println(response);\n    }\n}"
          }
        ]
      },
      "post": {
        "operationId": "fetchPagePost",
        "summary": "Fetch a page with a POST",
        "description": "Send a POST to the target through Zenrows. Takes the same query parameters as fetchPage; the request body is forwarded to the target as is, and the response carries the target's content.",
        "tags": [
          "Fetch"
        ],
        "requestBody": {
          "description": "Forwarded to the target as is.",
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            },
            "application/json": {
              "schema": {}
            },
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The target's content, in the shape the request asked for: HTML by default, Markdown or plaintext with `response_type`, a PDF or PNG/JPEG binary for `response_type=pdf` and the screenshot parameters, and JSON for `extract`, `css_extractor`, `autoparse` or `json_response`.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "The page as returned by the target."
                },
                "example": "<!doctype html>\n<html lang=\"en-US\">\n<head>\n<title>Ecommerce Test Site to Learn Web Scraping</title>\n</head>\n<body>\n<h1>Shop</h1>\n...\n</body>\n</html>"
              },
              "text/markdown": {
                "schema": {
                  "type": "string",
                  "description": "The page converted to Markdown."
                },
                "example": "[Ecommerce Test Site to Learn Web Scraping](https://www.scrapingcourse.com/ecommerce/)\n\n# Shop\n\n- [Abominable Hoodie](https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/) $69.00\n..."
              },
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "The page as plaintext."
                },
                "example": "Ecommerce Test Site to Learn Web Scraping\nShop\nAbominable Hoodie $69.00\n..."
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Structured output: the extracted fields, the autoparsed record, or the JSON envelope with captured network requests.",
                  "additionalProperties": true
                },
                "example": {
                  "html": "<!doctype html>\n<html lang=\"en-US\">...</html>",
                  "parsed": {
                    "breadcrumbs": [
                      {
                        "name": "Home",
                        "position": 1,
                        "url": "https://www.scrapingcourse.com/ecommerce"
                      }
                    ],
                    "product": {
                      "name": "Abominable Hoodie",
                      "availability": "out_of_stock",
                      "category": "Hoodies & Sweatshirts"
                    }
                  }
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "The page rendered to PDF."
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "Screenshot of the page or of the selected element."
                }
              }
            },
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "400": {
            "description": "The request is malformed, or a parameter combination is not allowed.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "REQS004",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Invalid value provided for 'js_render' parameter; invalid boolean value 'maybe' (REQS004)",
                  "type": "https://docs.zenrows.com/api-error-codes#REQS004"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "403": {
            "description": "With `extract=auto`, error `REQS007`: the domain, or this page type on it, has not been prepared for Extract yet. The message names the domain. The request is not charged and no HTML is returned. Prepare the domain with `requestExtractDomain`, then retry once it reports `ready`. Documented at https://docs.zenrows.com/api-error-codes#REQS007.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "REQS007",
                  "detail": "Extract has not been prepared for example.org yet. Ask for it with POST /v1/extract/prepared-domains, then retry once it reports ready. GET /v1/extract/domains lists what Extract serves today.",
                  "instance": "/v1",
                  "status": 403,
                  "title": "Extract is not prepared for the requested domain (example.org) (REQS007)",
                  "type": "https://docs.zenrows.com/api-error-codes#REQS007"
                }
              }
            }
          },
          "422": {
            "description": "Zenrows reached the target but could not return it under the requested configuration. With `extract`, the lowercase code `no_data_extracted` means something else: Extract knows this page type and applied its extraction, but no field came back filled. That answer is not charged, carries no HTML, and comes back the same on a retry, so do not retry it; check that the page rendered fully instead. The lowercase code `blocked_document` means the page Zenrows fetched was a bot challenge, an error page or a page that had not finished loading, so Extract had nothing real to read. It is not charged either; retry with `js_render=true` and/or `premium_proxy=true`, or with Adaptive Stealth Mode (`mode=auto`). Documented at https://docs.zenrows.com/api-error-codes#no_data_extracted.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "RESP001",
                  "detail": "The target could not be returned under this configuration. Try js_render=true and premium_proxy=true, or mode=auto.",
                  "instance": "/v1",
                  "status": 422,
                  "title": "Could not get content (RESP001)",
                  "type": "https://docs.zenrows.com/api-error-codes#RESP001"
                }
              }
            }
          },
          "429": {
            "description": "Error `AUTH008`: every concurrency slot on the plan is occupied. There is no fixed requests-per-minute quota to wait out and no Retry-After to read: a slot frees when one of your requests in flight finishes. Read `Concurrency-Remaining` on any response to pace yourself, and back off exponentially before retrying. Documented at https://docs.zenrows.com/api-error-codes#AUTH008 and https://docs.zenrows.com/fetch/features/concurrency.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH008",
                  "detail": "Every concurrency slot on the plan is in use. Retry when a request in flight finishes.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Concurrency limit reached (AUTH008)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH008"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "fetchPagePut",
        "summary": "Fetch a page with a PUT",
        "description": "Send a PUT to the target through Zenrows. Takes the same query parameters as fetchPage; the request body is forwarded to the target as is, and the response carries the target's content.",
        "tags": [
          "Fetch"
        ],
        "requestBody": {
          "description": "Forwarded to the target as is.",
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            },
            "application/json": {
              "schema": {}
            },
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The target's content, in the shape the request asked for: HTML by default, Markdown or plaintext with `response_type`, a PDF or PNG/JPEG binary for `response_type=pdf` and the screenshot parameters, and JSON for `extract`, `css_extractor`, `autoparse` or `json_response`.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "The page as returned by the target."
                },
                "example": "<!doctype html>\n<html lang=\"en-US\">\n<head>\n<title>Ecommerce Test Site to Learn Web Scraping</title>\n</head>\n<body>\n<h1>Shop</h1>\n...\n</body>\n</html>"
              },
              "text/markdown": {
                "schema": {
                  "type": "string",
                  "description": "The page converted to Markdown."
                },
                "example": "[Ecommerce Test Site to Learn Web Scraping](https://www.scrapingcourse.com/ecommerce/)\n\n# Shop\n\n- [Abominable Hoodie](https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/) $69.00\n..."
              },
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "The page as plaintext."
                },
                "example": "Ecommerce Test Site to Learn Web Scraping\nShop\nAbominable Hoodie $69.00\n..."
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Structured output: the extracted fields, the autoparsed record, or the JSON envelope with captured network requests.",
                  "additionalProperties": true
                },
                "example": {
                  "html": "<!doctype html>\n<html lang=\"en-US\">...</html>",
                  "parsed": {
                    "breadcrumbs": [
                      {
                        "name": "Home",
                        "position": 1,
                        "url": "https://www.scrapingcourse.com/ecommerce"
                      }
                    ],
                    "product": {
                      "name": "Abominable Hoodie",
                      "availability": "out_of_stock",
                      "category": "Hoodies & Sweatshirts"
                    }
                  }
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "The page rendered to PDF."
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "Screenshot of the page or of the selected element."
                }
              }
            },
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "400": {
            "description": "The request is malformed, or a parameter combination is not allowed.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "REQS004",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Invalid value provided for 'js_render' parameter; invalid boolean value 'maybe' (REQS004)",
                  "type": "https://docs.zenrows.com/api-error-codes#REQS004"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "403": {
            "description": "With `extract=auto`, error `REQS007`: the domain, or this page type on it, has not been prepared for Extract yet. The message names the domain. The request is not charged and no HTML is returned. Prepare the domain with `requestExtractDomain`, then retry once it reports `ready`. Documented at https://docs.zenrows.com/api-error-codes#REQS007.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "REQS007",
                  "detail": "Extract has not been prepared for example.org yet. Ask for it with POST /v1/extract/prepared-domains, then retry once it reports ready. GET /v1/extract/domains lists what Extract serves today.",
                  "instance": "/v1",
                  "status": 403,
                  "title": "Extract is not prepared for the requested domain (example.org) (REQS007)",
                  "type": "https://docs.zenrows.com/api-error-codes#REQS007"
                }
              }
            }
          },
          "422": {
            "description": "Zenrows reached the target but could not return it under the requested configuration. With `extract`, the lowercase code `no_data_extracted` means something else: Extract knows this page type and applied its extraction, but no field came back filled. That answer is not charged, carries no HTML, and comes back the same on a retry, so do not retry it; check that the page rendered fully instead. The lowercase code `blocked_document` means the page Zenrows fetched was a bot challenge, an error page or a page that had not finished loading, so Extract had nothing real to read. It is not charged either; retry with `js_render=true` and/or `premium_proxy=true`, or with Adaptive Stealth Mode (`mode=auto`). Documented at https://docs.zenrows.com/api-error-codes#no_data_extracted.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "RESP001",
                  "detail": "The target could not be returned under this configuration. Try js_render=true and premium_proxy=true, or mode=auto.",
                  "instance": "/v1",
                  "status": 422,
                  "title": "Could not get content (RESP001)",
                  "type": "https://docs.zenrows.com/api-error-codes#RESP001"
                }
              }
            }
          },
          "429": {
            "description": "Error `AUTH008`: every concurrency slot on the plan is occupied. There is no fixed requests-per-minute quota to wait out and no Retry-After to read: a slot frees when one of your requests in flight finishes. Read `Concurrency-Remaining` on any response to pace yourself, and back off exponentially before retrying. Documented at https://docs.zenrows.com/api-error-codes#AUTH008 and https://docs.zenrows.com/fetch/features/concurrency.",
            "headers": {
              "Concurrency-Limit": {
                "$ref": "#/components/headers/ConcurrencyLimit"
              },
              "Concurrency-Remaining": {
                "$ref": "#/components/headers/ConcurrencyRemaining"
              },
              "X-Request-Cost": {
                "$ref": "#/components/headers/XRequestCost"
              },
              "X-Request-Credits": {
                "$ref": "#/components/headers/XRequestCredits"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH008",
                  "detail": "Every concurrency slot on the plan is in use. Retry when a request in flight finishes.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Concurrency limit reached (AUTH008)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH008"
                }
              }
            }
          }
        }
      }
    },
    "/extract/domains": {
      "get": {
        "operationId": "listExtractDomains",
        "summary": "List the domains Extract serves",
        "description": "Every domain Extract can handle right now. A domain in this list is one you can send `extract=auto` to; a domain missing from it answers `REQS007`. Costs no credits. Documented at https://docs.zenrows.com/extract/endpoints.",
        "tags": [
          "Extract"
        ],
        "security": [
          {
            "apiKeyQuery": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The domains Extract serves.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domains": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "domain": {
                            "type": "string",
                            "description": "The registrable domain. It covers every subdomain."
                          },
                          "verticals": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "The IAB content categories of the pages Extract serves on this domain. May be empty."
                          },
                          "warm": {
                            "type": "boolean",
                            "description": "Always `true` today."
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "domains": [
                    {
                      "domain": "scrapingcourse.com",
                      "verticals": [
                        "Shopping"
                      ],
                      "warm": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          }
        }
      }
    },
    "/extract/prepared-domains": {
      "post": {
        "operationId": "requestExtractDomain",
        "summary": "Ask for a domain to be prepared for Extract",
        "description": "Submit a domain for preparation, within a monthly allowance. The submission is accepted immediately and works through discovery, preparation and verification, typically in minutes: poll `getExtractDomainStatus` instead of blocking. Send 1 to 5 `example_urls` when you can; they replace discovery. One works; we recommend 3 or more of the same page type (e.g. 3 product pages), because Extract compares pages of one type to check the fields it found and fill in fields one page is missing. Several page types can share the 5 (e.g. 3 product pages + 2 search-result pages). Submitting a domain that is already prepared returns its current record rather than starting again, so it does not add new page types. Send an `Idempotency-Key` header to make a retry safe. Costs no credits. Documented at https://docs.zenrows.com/extract/endpoints.",
        "tags": [
          "Extract"
        ],
        "security": [
          {
            "apiKeyQuery": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "The same key returns the original submission instead of spending a second allowance slot.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "The domain to prepare, without scheme.",
                    "example": "scrapingcourse.com"
                  },
                  "example_urls": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uri"
                    },
                    "description": "1 to 5 URLs on that domain. One works; we recommend 3 or more of the same page type (e.g. 3 product pages), because Extract compares pages of one type to check the fields it found and fill in fields one page is missing. Several page types can share the 5 (e.g. 3 product pages + 2 search-result pages). When present, they replace discovery.",
                    "example": [
                      "https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/",
                      "https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/",
                      "https://www.scrapingcourse.com/ecommerce/product/aeon-capri/"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. The body is the submission in the same shape `getExtractDomainStatus` returns.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractPreparation"
                },
                "example": {
                  "domain": "scrapingcourse.com",
                  "status": "preparing",
                  "state": "received",
                  "submitted_at": "2026-10-15T10:00:00Z",
                  "updated_at": "2026-10-15T10:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: the body is missing or malformed. `reason` carries a machine-readable tag such as `invalid_domain`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractEndpointError"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "409": {
            "description": "`in_progress`: the domain already has a preparation running, so poll its status. Or `idempotency_conflict`: the same `Idempotency-Key` was reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractEndpointError"
                }
              }
            }
          },
          "429": {
            "description": "`out_of_allowance`: no preparation slots left this month. See `getExtractAllowance`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractEndpointError"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listExtractPreparations",
        "summary": "List the domains your account submitted",
        "description": "Every domain this account has submitted for preparation, with the monthly allowance alongside it. This lists what you submitted, not every domain Extract serves (see `listExtractDomains`). Costs no credits. Documented at https://docs.zenrows.com/extract/endpoints.",
        "tags": [
          "Extract"
        ],
        "security": [
          {
            "apiKeyQuery": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The account's submissions and allowance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "allowance": {
                      "type": "object",
                      "description": "Domains this account can still ask to have prepared this month. A failure that returns its slot is not counted in `used`.",
                      "properties": {
                        "used": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "remaining": {
                          "type": "integer"
                        },
                        "month": {
                          "type": "string",
                          "description": "The UTC calendar month the count applies to, `YYYY-MM`. The allowance resets when it rolls over.",
                          "example": "2026-09"
                        }
                      }
                    },
                    "domains": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExtractPreparation"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          }
        }
      }
    },
    "/extract/prepared-domains/allowance": {
      "get": {
        "operationId": "getExtractAllowance",
        "summary": "Read the monthly preparation allowance",
        "description": "How many domains this account can still ask to have prepared this month. Costs no credits. Documented at https://docs.zenrows.com/extract/endpoints.",
        "tags": [
          "Extract"
        ],
        "security": [
          {
            "apiKeyQuery": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The allowance for the current month.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Domains this account can still ask to have prepared this month. A failure that returns its slot is not counted in `used`.",
                  "properties": {
                    "used": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "remaining": {
                      "type": "integer"
                    },
                    "month": {
                      "type": "string",
                      "description": "The UTC calendar month the count applies to, `YYYY-MM`. The allowance resets when it rolls over.",
                      "example": "2026-09"
                    }
                  }
                },
                "example": {
                  "used": 3,
                  "limit": 10,
                  "remaining": 7,
                  "month": "2026-10"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          }
        }
      }
    },
    "/extract/prepared-domains/{domain}": {
      "get": {
        "operationId": "getExtractDomainStatus",
        "summary": "Track a domain's preparation",
        "description": "How far a submission has got. Branch on `status` (`preparing`, `ready`, `failed`); `state` is the finer-grained step. Costs no credits. Documented at https://docs.zenrows.com/extract/endpoints.",
        "tags": [
          "Extract"
        ],
        "security": [
          {
            "apiKeyQuery": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "The domain, without scheme.",
            "schema": {
              "type": "string"
            },
            "example": "scrapingcourse.com"
          }
        ],
        "responses": {
          "200": {
            "description": "The domain's most recent submission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractPreparation"
                },
                "example": {
                  "domain": "scrapingcourse.com",
                  "status": "ready",
                  "state": "ready",
                  "roles": [
                    {
                      "role": "detail",
                      "status": "ready"
                    }
                  ],
                  "submitted_at": "2026-09-11T14:33:45Z",
                  "updated_at": "2026-09-11T14:35:03Z"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: this domain has never been submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractEndpointError"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/signup": {
      "post": {
        "operationId": "createAgentAccount",
        "summary": "Get an API key for your agent, no signup required",
        "description": "Start using Zenrows from your agent without signing up. This call returns a working API key straight away: no account setup, no login, no payment details. The key works right away on the free plan. The account is on the Free plan from signup: 5,000 credits per month, renewed monthly. A person who wants to own it opens `claimUrl` and claims it; the same key keeps working.\n\nContract published at https://app.zenrows.com/agent-onboarding/auth.md, and advertised as `agent_auth.signup_endpoint` in https://app.zenrows.com/.well-known/oauth-protected-resource.",
        "tags": [
          "Onboarding"
        ],
        "servers": [
          {
            "url": "https://app.zenrows.com",
            "description": "Dashboard host, which serves the agent onboarding surface"
          }
        ],
        "security": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "No fields are required. An empty body is the normal call. After a `428`, send the question's id and your answer.",
                "additionalProperties": false,
                "properties": {
                  "challenge_id": {
                    "type": "string",
                    "description": "The `challenge.id` from a `428` response."
                  },
                  "answer": {
                    "type": "string",
                    "description": "Your answer to `challenge.prompt`. Case and punctuation do not matter."
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "description": "The short form of the answer, as the `428` message's curl shows it.",
                "properties": {
                  "c": {
                    "type": "string",
                    "description": "The `challenge.id` from a `428` response."
                  },
                  "a": {
                    "type": "string",
                    "description": "Your answer to `challenge.prompt`."
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-ZR-Agent-Id",
            "in": "header",
            "required": false,
            "description": "Optional provenance, anonymous and free of personal data.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-ZR-Client",
            "in": "header",
            "required": false,
            "description": "Optional name of the calling client.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-ZR-Source",
            "in": "header",
            "required": false,
            "description": "Optional origin of the signup.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "The account exists and the key works immediately.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "apiKey",
                    "accountId",
                    "claimUrl",
                    "trialEndsAt"
                  ],
                  "properties": {
                    "apiKey": {
                      "type": "string",
                      "description": "Pass it as the `apikey` query parameter to Fetch, or as `X-API-Key` to Batch."
                    },
                    "accountId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "claimUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "Where a person claims the account to own it. Show this link to a human; do not sit on it."
                    },
                    "trialEndsAt": {
                      "type": "string",
                      "format": "date-time",
                      "description": "End of the first monthly period (signup + 1 month). The Free plan renews monthly; this value is not refreshed."
                    }
                  }
                },
                "example": {
                  "apiKey": "8d1c2e9f0a7b4c3d5e6f7a8b9c0d1e2f3a4b5c6d",
                  "accountId": "3f2b8c1e-5a4d-4e7f-9b6a-1c2d3e4f5a6b",
                  "claimUrl": "https://app.zenrows.com/claim/q7Rk2LmX9pTz?utm_source=agent",
                  "trialEndsAt": "2026-11-15T10:00:00+00:00"
                }
              }
            }
          },
          "428": {
            "description": "Error `challenge_required`: signup may first ask one short question that the agent answers itself. Answer with the same POST, from the same network, within `challenge.expires_in` seconds. A wrong or expired answer returns another `428` with a new question; each question can be answered once.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message",
                    "challenge"
                  ],
                  "properties": {
                    "error": {
                      "type": "string",
                      "enum": [
                        "challenge_required"
                      ]
                    },
                    "message": {
                      "type": "string",
                      "description": "The question, with a ready-to-run curl to answer it."
                    },
                    "challenge": {
                      "type": "object",
                      "required": [
                        "id",
                        "prompt",
                        "expires_in"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "Send it back as `challenge_id` (or `c`)."
                        },
                        "prompt": {
                          "type": "string",
                          "description": "The question: which word is in a category, which word does not belong (the answer is always a word from the question)."
                        },
                        "expires_in": {
                          "type": "integer",
                          "description": "Seconds left to answer."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "To create a Zenrows account, answer: which of norway, walrus, pear is a country? Run: curl -X POST https://app.zenrows.com/api/agent/signup -d c=f4261db6 -d a=ANSWER",
                  "error": "challenge_required",
                  "challenge": {
                    "id": "f4261db6",
                    "prompt": "which of norway, walrus, pear is a country?",
                    "expires_in": 600
                  }
                }
              }
            }
          },
          "429": {
            "description": "Error `rate_limited`: three signups per client IP per 24 hours. Wait; do not go looking for another signup URL. Or error `challenge_locked`: too many questions or wrong answers from this network; wait an hour (`Retry-After`: 3600) or use an existing API key.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupError"
                }
              }
            }
          },
          "500": {
            "description": "Error `signup_failed`. Retry once with backoff, then hand it to a human.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupError"
                }
              }
            }
          },
          "503": {
            "description": "Error `signup_disabled`: the kill switch is on. Retry later, and do not invent another signup URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupError"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/account": {
      "get": {
        "operationId": "getAgentAccount",
        "summary": "Check whether a person has claimed this account",
        "description": "Report the claim state of an account created by createAgentAccount. Claiming does not rotate the key, so an agent keeps working across it; this is how it learns a human took ownership. Never contains an email or any secret.",
        "tags": [
          "Onboarding"
        ],
        "servers": [
          {
            "url": "https://app.zenrows.com",
            "description": "Dashboard host, which serves the agent onboarding surface"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The account and its claim state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "accountId",
                    "claimed",
                    "isAgent"
                  ],
                  "properties": {
                    "accountId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "claimed": {
                      "type": "boolean",
                      "description": "Whether a person has taken ownership."
                    },
                    "isAgent": {
                      "type": "boolean",
                      "description": "Whether the account was created by the agent signup."
                    },
                    "trialEndsAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time",
                      "description": "End of the first monthly period (signup + 1 month). The Free plan renews monthly; this value is not refreshed."
                    }
                  }
                },
                "example": {
                  "accountId": "3f2b8c1e-5a4d-4e7f-9b6a-1c2d3e4f5a6b",
                  "claimed": false,
                  "isAgent": true,
                  "trialEndsAt": "2026-11-15T10:00:00+00:00"
                }
              }
            }
          },
          "401": {
            "description": "Error `invalid_key`: the key is missing or unknown.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupError"
                }
              }
            }
          }
        }
      }
    },
    "/subscriptions/self/details": {
      "get": {
        "operationId": "getSubscriptionDetails",
        "summary": "Read the plan behind the key",
        "description": "Return the calling key's plan: credit allowance, credits used, and the concurrency it is allowed. Use it to budget before a large run.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "responses": {
          "200": {
            "description": "Plan, credit and concurrency figures for the calling key.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "The subscription's state, for example `ACTIVE`."
                    },
                    "period_starts_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "period_ends_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the credit allowance renews."
                    },
                    "usage": {
                      "type": "number",
                      "description": "Spend this period, in US dollars."
                    },
                    "usage_credits": {
                      "type": "integer",
                      "description": "Credits used this period, across products."
                    },
                    "credit_limit": {
                      "type": "integer",
                      "description": "Credits the plan includes for the period."
                    },
                    "usage_percent": {
                      "type": "integer",
                      "description": "`usage_credits` as a whole percentage of `credit_limit`."
                    },
                    "plan": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "price": {
                          "type": "number"
                        },
                        "unit_cost": {
                          "type": "number",
                          "description": "Price of one credit, in US dollars."
                        },
                        "recurrence": {
                          "type": "string",
                          "examples": [
                            "MONTHLY",
                            "YEARLY"
                          ]
                        },
                        "products": {
                          "type": "object",
                          "description": "Usage per product. `api` also carries the plan's concurrency.",
                          "properties": {
                            "api": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "usage": {
                                  "type": "number",
                                  "description": "Spend this period, in US dollars."
                                },
                                "usage_credits": {
                                  "type": "integer",
                                  "description": "Credits used this period."
                                },
                                "concurrency": {
                                  "type": "object",
                                  "properties": {
                                    "limit": {
                                      "type": "integer"
                                    },
                                    "usage": {
                                      "type": "integer"
                                    }
                                  }
                                }
                              }
                            },
                            "extract": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "usage": {
                                  "type": "number",
                                  "description": "Spend this period, in US dollars."
                                },
                                "usage_credits": {
                                  "type": "integer",
                                  "description": "Credits used this period."
                                }
                              }
                            },
                            "scraping_browser": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "usage": {
                                  "type": "number",
                                  "description": "Spend this period, in US dollars."
                                },
                                "usage_credits": {
                                  "type": "integer",
                                  "description": "Credits used this period."
                                }
                              }
                            },
                            "proxy_residential": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "usage": {
                                  "type": "number",
                                  "description": "Spend this period, in US dollars."
                                },
                                "usage_credits": {
                                  "type": "integer",
                                  "description": "Credits used this period."
                                }
                              }
                            },
                            "data_apis": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "usage": {
                                  "type": "number",
                                  "description": "Spend this period, in US dollars."
                                },
                                "usage_credits": {
                                  "type": "integer",
                                  "description": "Credits used this period."
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "top_ups": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Credit top-ups bought this period."
                    },
                    "api_key": {
                      "type": "object",
                      "properties": {
                        "caps": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          },
                          "description": "Credit caps set on the calling key."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": "ACTIVE",
                  "period_starts_at": "2026-10-01T00:00:00Z",
                  "period_ends_at": "2026-11-01T00:00:00Z",
                  "usage": 11.59,
                  "usage_credits": 42000,
                  "credit_limit": 250000,
                  "usage_percent": 16,
                  "plan": {
                    "name": "Launch",
                    "price": 69,
                    "unit_cost": 0.000276,
                    "recurrence": "MONTHLY",
                    "products": {
                      "api": {
                        "name": "WebScraping API",
                        "usage": 8.56,
                        "usage_credits": 31000,
                        "concurrency": {
                          "limit": 20,
                          "usage": 2
                        }
                      },
                      "extract": {
                        "name": "Extract",
                        "usage": 0,
                        "usage_credits": 0
                      },
                      "scraping_browser": {
                        "name": "Scraping Browser",
                        "usage": 3.03,
                        "usage_credits": 11000
                      },
                      "proxy_residential": {
                        "name": "Residential Proxies",
                        "usage": 0,
                        "usage_credits": 0
                      },
                      "data_apis": {
                        "name": "Data APIs",
                        "usage": 0,
                        "usage_credits": 0
                      }
                    }
                  },
                  "top_ups": [],
                  "api_key": {
                    "caps": []
                  }
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          }
        }
      }
    },
    "/jobs": {
      "post": {
        "operationId": "createBatchJob",
        "summary": "Create a batch job (many URLs in one request)",
        "description": "Submit a job. A closed job carries all its URLs up front in `tasks`; an open job (`status: open`) is created empty and receives URLs through addBatchTasks until one call sets `last_batch`. A scheduled job (`type: scheduled`) stores its URLs as a template and each fire creates a run. `zenrows_params` applies to every task and a per-task `zenrows_params` overrides it. Returns 201 under 10,000 inline tasks and 202 at or above that (or for a CSV input); the body is identical, so treat both the same. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#1-create-your-jobs.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional guard against creating duplicate jobs. Each key can be used once: the first submit with a key creates the job, and any later submit reusing it returns 409 `idempotency_key_conflict`, whether or not the body is identical. The original response is not replayed, so this is not a safe-retry token: if a submit fails midway, list your recent jobs to see whether it was created, then reuse its `job_id` or submit again with a new key.",
            "example": "nightly-2026-06-08"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "status"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "regular",
                      "scheduled"
                    ],
                    "description": "`regular` runs when submitted; `scheduled` runs on the `schedule`."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "closed",
                      "open"
                    ],
                    "description": "`closed` carries every URL now; `open` accepts URLs over time through addBatchTasks."
                  },
                  "name": {
                    "type": "string",
                    "description": "Your own label for the job."
                  },
                  "external_id": {
                    "type": "string",
                    "description": "Your own identifier for the job."
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Your own key-value data, returned with the job."
                  },
                  "zenrows_params": {
                    "type": "object",
                    "description": "Fetch parameters applied to every task, with the names the fetchPage operation uses.",
                    "additionalProperties": true
                  },
                  "tasks": {
                    "type": "array",
                    "description": "The URLs to run, up to 100,000 per submit. Omit for an open job and when `file_input_id` is set.",
                    "maxItems": 100000,
                    "items": {
                      "$ref": "#/components/schemas/BatchTask"
                    }
                  },
                  "file_input_id": {
                    "type": "string",
                    "description": "From uploadBatchInput, to run the job from an uploaded CSV instead of inline `tasks`. Always answers 202."
                  },
                  "schedule": {
                    "$ref": "#/components/schemas/BatchSchedule"
                  },
                  "webhook": {
                    "$ref": "#/components/schemas/BatchWebhook"
                  }
                }
              },
              "example": {
                "type": "regular",
                "status": "closed",
                "zenrows_params": {
                  "js_render": "true",
                  "response_type": "markdown"
                },
                "tasks": [
                  {
                    "url": "https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/",
                    "external_id": "sku-1042"
                  },
                  {
                    "url": "https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/",
                    "external_id": "sku-1043",
                    "zenrows_params": {
                      "proxy_country": "de"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Job accepted, under 10,000 inline tasks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobSubmitted"
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "status": "closed",
                  "accepted_tasks": 2,
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "running",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 2,
                      "completed": 0,
                      "successful": 0,
                      "failed": 0
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  }
                }
              }
            }
          },
          "202": {
            "description": "Job accepted, 10,000 tasks or more, or a CSV input. Task rows keep writing for a few seconds, so results pages can be partial at first, and addBatchTasks can answer 409 meanwhile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobSubmitted"
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "status": "closed",
                  "accepted_tasks": 2,
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "running",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 2,
                      "completed": 0,
                      "successful": 0,
                      "failed": 0
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "409": {
            "description": "`idempotency_key_conflict`: the Idempotency-Key was already used. No job was created by this request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "idempotency_key_conflict",
                  "detail": "Idempotency key already used.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "Idempotency key already used (idempotency_key_conflict)",
                  "type": "https://docs.zenrows.com/api-error-codes#idempotency_key_conflict"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listBatchJobs",
        "summary": "List batch jobs",
        "description": "Page through the jobs on the account, newest first. Keep paging while `next_cursor` is present.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filter by whether the job still accepts tasks.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "closed"
              ]
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter by job type.",
            "schema": {
              "type": "string",
              "enum": [
                "regular",
                "scheduled"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "How many jobs to return.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of jobs.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Job"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Absent or `null` on the last page."
                    }
                  }
                },
                "example": {
                  "jobs": [
                    {
                      "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                      "type": "regular",
                      "status": "closed",
                      "format": "markdown",
                      "zenrows_params": {
                        "response_type": "markdown"
                      },
                      "created_at": "2026-10-08T14:55:52Z",
                      "updated_at": "2026-10-08T14:55:52Z",
                      "latest_run": {
                        "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                        "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                        "run_sequence": 1,
                        "status": "completed",
                        "trigger": "manual",
                        "last_batch_received": false,
                        "stats": {
                          "total": 3,
                          "completed": 3,
                          "successful": 3,
                          "failed": 0,
                          "spend": {
                            "credits": 3,
                            "cost": 0.00027
                          }
                        },
                        "created_at": "2026-10-08T14:55:52Z",
                        "updated_at": "2026-10-08T14:56:06Z"
                      }
                    }
                  ],
                  "next_cursor": "01M471FTKHRW361M68T9PX902S"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}": {
      "get": {
        "operationId": "getBatchJob",
        "summary": "Read a job",
        "description": "The job and its latest run: progress in `latest_run.stats`, spend in `latest_run.stats.spend`. Poll with backoff until `latest_run.status` is terminal, or take a webhook. A deleted job answers 404.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job and its latest run.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "type": "regular",
                  "status": "closed",
                  "format": "markdown",
                  "zenrows_params": {
                    "response_type": "markdown"
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:55:52Z",
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "completed",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 3,
                      "completed": 3,
                      "successful": 3,
                      "failed": 0,
                      "spend": {
                        "credits": 3,
                        "cost": 0.00027
                      }
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: the job, run or task does not exist or is not yours.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "not_found",
                  "detail": "Job not found.",
                  "instance": "/v1",
                  "status": 404,
                  "title": "Job not found (not_found)",
                  "type": "https://docs.zenrows.com/api-error-codes#not_found"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/tasks": {
      "post": {
        "operationId": "addBatchTasks",
        "summary": "Add URLs to an open job",
        "description": "Append up to 10,000 URLs to an open job. Send `last_batch: true` on the final call to close it; later additions then return 409. Can also return 409 for a few seconds while a very large submission is still being written: retry.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tasks"
                ],
                "properties": {
                  "tasks": {
                    "type": "array",
                    "maxItems": 10000,
                    "items": {
                      "$ref": "#/components/schemas/BatchTask"
                    }
                  },
                  "last_batch": {
                    "type": "boolean",
                    "description": "Closes the job after this batch."
                  }
                }
              },
              "example": {
                "tasks": [
                  {
                    "url": "https://www.scrapingcourse.com/ecommerce/page/2/"
                  }
                ],
                "last_batch": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tasks were accepted.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accepted_tasks": {
                      "type": "integer"
                    },
                    "job_status": {
                      "type": "string",
                      "enum": [
                        "open",
                        "closed"
                      ]
                    },
                    "latest_run": {
                      "$ref": "#/components/schemas/Run"
                    }
                  }
                },
                "example": {
                  "accepted_tasks": 1,
                  "job_status": "closed",
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "completed",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 3,
                      "completed": 3,
                      "successful": 3,
                      "failed": 0,
                      "spend": {
                        "credits": 3,
                        "cost": 0.00027
                      }
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "409": {
            "description": "The job is closed, or a large submission is still being written.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "conflict",
                  "detail": "Job is closed.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "Job is closed (conflict)",
                  "type": "https://docs.zenrows.com/api-error-codes#conflict"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/close": {
      "post": {
        "operationId": "closeBatchJob",
        "summary": "Close an open job",
        "description": "Lock an open job so it accepts no further tasks. Equivalent to `last_batch` on the last add.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job, now closed.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "type": "regular",
                  "status": "closed",
                  "format": "markdown",
                  "zenrows_params": {
                    "response_type": "markdown"
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:55:52Z",
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "completed",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 3,
                      "completed": 3,
                      "successful": 3,
                      "failed": 0,
                      "spend": {
                        "credits": 3,
                        "cost": 0.00027
                      }
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/stop": {
      "post": {
        "operationId": "stopBatchRun",
        "summary": "Stop the current run",
        "description": "Move the running or pending run to `stopped`, which is terminal. Tasks in flight may finish; pending ones stay as they are. Idempotent on a stopped run; 409 when the run already completed or was deleted.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run, stopped.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                },
                "example": {
                  "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "run_sequence": 1,
                  "status": "stopped",
                  "trigger": "manual",
                  "last_batch_received": false,
                  "stats": {
                    "total": 3,
                    "completed": 1,
                    "successful": 1,
                    "failed": 0,
                    "spend": {
                      "credits": 1,
                      "cost": 0.00009
                    }
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:56:06Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: the job, run or task does not exist or is not yours.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "not_found",
                  "detail": "Job not found.",
                  "instance": "/v1",
                  "status": 404,
                  "title": "Job not found (not_found)",
                  "type": "https://docs.zenrows.com/api-error-codes#not_found"
                }
              }
            }
          },
          "409": {
            "description": "`run_not_terminal` or `conflict`: the run is in a state this action does not apply to.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "conflict",
                  "detail": "The run already completed.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "The run already completed (conflict)",
                  "type": "https://docs.zenrows.com/api-error-codes#conflict"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/pause": {
      "post": {
        "operationId": "pauseBatchRun",
        "summary": "Pause the current run",
        "description": "Stop dispatching new tasks without ending the run; `status` does not change, `pause_state` does. Idempotent; 409 when the latest run is terminal. Not the same as pausing a schedule (setBatchScheduleState).",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run, paused.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                },
                "example": {
                  "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "run_sequence": 1,
                  "status": "running",
                  "trigger": "manual",
                  "last_batch_received": false,
                  "stats": {
                    "total": 3,
                    "completed": 1,
                    "successful": 1,
                    "failed": 0,
                    "spend": {
                      "credits": 1,
                      "cost": 0.00009
                    }
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:56:06Z",
                  "pause_state": "paused"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: the job, run or task does not exist or is not yours.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "not_found",
                  "detail": "Job not found.",
                  "instance": "/v1",
                  "status": 404,
                  "title": "Job not found (not_found)",
                  "type": "https://docs.zenrows.com/api-error-codes#not_found"
                }
              }
            }
          },
          "409": {
            "description": "`run_not_terminal` or `conflict`: the run is in a state this action does not apply to.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "conflict",
                  "detail": "The run already completed.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "The run already completed (conflict)",
                  "type": "https://docs.zenrows.com/api-error-codes#conflict"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/resume": {
      "post": {
        "operationId": "resumeBatchRun",
        "summary": "Resume a paused run",
        "description": "Continue dispatching the remaining tasks of a paused run. Idempotent; 409 when the latest run is terminal.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run, resumed.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                },
                "example": {
                  "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "run_sequence": 1,
                  "status": "running",
                  "trigger": "manual",
                  "last_batch_received": false,
                  "stats": {
                    "total": 3,
                    "completed": 1,
                    "successful": 1,
                    "failed": 0,
                    "spend": {
                      "credits": 1,
                      "cost": 0.00009
                    }
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:56:06Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: the job, run or task does not exist or is not yours.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "not_found",
                  "detail": "Job not found.",
                  "instance": "/v1",
                  "status": 404,
                  "title": "Job not found (not_found)",
                  "type": "https://docs.zenrows.com/api-error-codes#not_found"
                }
              }
            }
          },
          "409": {
            "description": "`run_not_terminal` or `conflict`: the run is in a state this action does not apply to.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "conflict",
                  "detail": "The run already completed.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "The run already completed (conflict)",
                  "type": "https://docs.zenrows.com/api-error-codes#conflict"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/cancel": {
      "post": {
        "operationId": "cancelBatchJob",
        "summary": "Cancel the current run",
        "description": "An alias of stopBatchRun.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run, stopped.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                },
                "example": {
                  "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "run_sequence": 1,
                  "status": "stopped",
                  "trigger": "manual",
                  "last_batch_received": false,
                  "stats": {
                    "total": 3,
                    "completed": 1,
                    "successful": 1,
                    "failed": 0,
                    "spend": {
                      "credits": 1,
                      "cost": 0.00009
                    }
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:56:06Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: the job, run or task does not exist or is not yours.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "not_found",
                  "detail": "Job not found.",
                  "instance": "/v1",
                  "status": 404,
                  "title": "Job not found (not_found)",
                  "type": "https://docs.zenrows.com/api-error-codes#not_found"
                }
              }
            }
          },
          "409": {
            "description": "`run_not_terminal` or `conflict`: the run is in a state this action does not apply to.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "conflict",
                  "detail": "The run already completed.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "The run already completed (conflict)",
                  "type": "https://docs.zenrows.com/api-error-codes#conflict"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/rerun": {
      "post": {
        "operationId": "rerunBatchJob",
        "summary": "Run a job again",
        "description": "Start a new run of the same job: everything, or only what failed. Tasks that already succeeded are carried over, not fetched or charged again. Partial reruns are only allowed within 10 days of the original run finishing (409 `partial_rerun_window_expired`). Send no body.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Rerun only these task outcomes. Omit for a full rerun.",
            "schema": {
              "type": "string",
              "enum": [
                "failed",
                "failed,pending"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The new run.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "rerun_of": {
                      "type": "string",
                      "description": "The run this one retries."
                    },
                    "retried_tasks": {
                      "type": "integer"
                    },
                    "inherited_tasks": {
                      "type": "integer",
                      "description": "Already-successful tasks carried over."
                    },
                    "latest_run": {
                      "$ref": "#/components/schemas/Run"
                    }
                  }
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "status": "closed",
                  "rerun_of": "01M4E06YS7VZPY4G25DV6FR3B8",
                  "retried_tasks": 1,
                  "inherited_tasks": 2,
                  "latest_run": {
                    "run_id": "01M4F2K9P3QZ8W7T6Y5X4V3B2N",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 2,
                    "status": "running",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 3,
                      "completed": 2,
                      "successful": 2,
                      "failed": 0
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "409": {
            "description": "`partial_rerun_window_expired`, or the job's run is not finished.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "partial_rerun_window_expired",
                  "detail": "Partial reruns are only allowed within 10 days of the original run.",
                  "instance": "/v1",
                  "status": 409,
                  "title": "Partial reruns are only allowed within 10 days of the original run (partial_rerun_window_expired)",
                  "type": "https://docs.zenrows.com/api-error-codes#partial_rerun_window_expired"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/results": {
      "get": {
        "operationId": "getBatchResults",
        "summary": "Read a job's results",
        "description": "Page through the per-URL results of the job's runs: status, a presigned `result_url` valid for 2 hours, your `external_id`, and `error` on failed rows. Results are kept 14 days after the run finishes. A failed task is a row, not an HTTP error.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by task outcome.",
            "schema": {
              "type": "string",
              "enum": [
                "successful",
                "failed",
                "all"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of task results.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TaskResult"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Absent or `null` on the last page."
                    }
                  }
                },
                "example": {
                  "results": [
                    {
                      "task_id": "01M4E06YS71KCFGK0KQYPXWNTA",
                      "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                      "url": "https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/",
                      "external_id": "sku-1043",
                      "status": "successful",
                      "type": "markdown",
                      "result_url": "https://results.example-bucket.s3.amazonaws.com/jobs/01M4E06YS7BDRECVN5QRHJA6HR/tasks/01M4E06YS71KCFGK0KQYPXWNTA.md?X-Amz-Expires=7200",
                      "created_at": "2026-10-08T14:55:52Z",
                      "updated_at": "2026-10-08T14:56:01Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/tasks/{task_id}/content": {
      "get": {
        "operationId": "getBatchTaskContent",
        "summary": "Download one task's content",
        "description": "The stored content of one task, in the format the job requested. 409 while the task is still pending; 422 when it failed, with the stored error as the body.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "task_id",
            "in": "path",
            "required": true,
            "description": "Identifier of one task (one URL) inside the job.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The task's content.",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string",
                  "description": "Stored page content."
                },
                "example": "[Ecommerce Test Site to Learn Web Scraping](https://www.scrapingcourse.com/ecommerce/)\n\n# Abominable Hoodie\n..."
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/runs": {
      "get": {
        "operationId": "listBatchRuns",
        "summary": "List a job's runs",
        "description": "Every run of the job, newest first, with its stats. Pages like listBatchJobs.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "How many runs to return.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job's runs.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Run"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "runs": [
                    {
                      "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                      "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                      "run_sequence": 1,
                      "status": "completed",
                      "trigger": "manual",
                      "last_batch_received": false,
                      "stats": {
                        "total": 3,
                        "completed": 3,
                        "successful": 3,
                        "failed": 0,
                        "spend": {
                          "credits": 3,
                          "cost": 0.00027
                        }
                      },
                      "created_at": "2026-10-08T14:55:52Z",
                      "updated_at": "2026-10-08T14:56:06Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/runs/{run_id}": {
      "delete": {
        "operationId": "deleteBatchRun",
        "summary": "Delete a run",
        "description": "Remove a run's stored results. The job and its other runs are kept. Idempotent.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run_id",
            "in": "path",
            "required": true,
            "description": "Identifier of one run of the job.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The run was deleted."
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/runs/{run_id}/exports": {
      "post": {
        "operationId": "createBatchExport",
        "summary": "Export a run as a ZIP",
        "description": "Ask for a bulk export of a run's content. It is prepared asynchronously: poll getBatchExport with the returned `export_id` until `status` is `completed`, then download `download_url`. An export expires 12 hours after it is created; a run over 100 GiB fails with an error instead of a partial archive. Send no body.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run_id",
            "in": "path",
            "required": true,
            "description": "Identifier of one run of the job.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The export, being prepared.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "export_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "description": "`completed` and `failed` are final; poll until one of them.",
                      "examples": [
                        "pending",
                        "completed",
                        "failed"
                      ]
                    },
                    "download_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Presigned ZIP link, once `completed`. Re-signed on each poll."
                    },
                    "error": {
                      "type": "string",
                      "description": "Why the export failed, when it did."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "12 hours after creation."
                    }
                  }
                },
                "example": {
                  "export_id": "exp_01M4F3A7C2D9E8B6",
                  "status": "pending",
                  "created_at": "2026-10-08T15:02:11Z",
                  "expires_at": "2026-10-09T03:02:11Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/runs/{run_id}/exports/{export_id}": {
      "get": {
        "operationId": "getBatchExport",
        "summary": "Check an export",
        "description": "Read an export's state. Poll until `status` is `completed` (then download `download_url`, re-signed on each poll) or `failed` (then read `error`).",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run_id",
            "in": "path",
            "required": true,
            "description": "Identifier of one run of the job.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "export_id",
            "in": "path",
            "required": true,
            "description": "The `export_id` returned when the export was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The export's status and, once completed, its download URL.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "export_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "description": "`completed` and `failed` are final; poll until one of them.",
                      "examples": [
                        "pending",
                        "completed",
                        "failed"
                      ]
                    },
                    "download_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Presigned ZIP link, once `completed`. Re-signed on each poll."
                    },
                    "error": {
                      "type": "string",
                      "description": "Why the export failed, when it did."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "12 hours after creation."
                    }
                  }
                },
                "example": {
                  "export_id": "exp_01M4F3A7C2D9E8B6",
                  "status": "completed",
                  "download_url": "https://results.example-bucket.s3.amazonaws.com/exports/exp_01M4F3A7C2D9E8B6.zip?X-Amz-Expires=7200",
                  "created_at": "2026-10-08T15:02:11Z",
                  "expires_at": "2026-10-09T03:02:11Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/schedule": {
      "put": {
        "operationId": "putBatchSchedule",
        "summary": "Set a job's schedule",
        "description": "Replace a scheduled job's schedule. Give exactly one of `at`, `rate` or `calendar`, plus `timezone` for `at` and `calendar`. Times of day are full hours and runs are at least 60 minutes apart.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchSchedule"
              },
              "example": {
                "calendar": {
                  "times_of_day": [
                    "09:00",
                    "18:00"
                  ],
                  "cadence": {
                    "weekly": {
                      "days": [
                        "mon",
                        "wed",
                        "fri"
                      ]
                    }
                  }
                },
                "timezone": "Europe/Berlin"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job with its new schedule.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "type": "scheduled",
                  "status": "closed",
                  "format": "markdown",
                  "zenrows_params": {
                    "response_type": "markdown"
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:55:52Z",
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "completed",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 3,
                      "completed": 3,
                      "successful": 3,
                      "failed": 0,
                      "spend": {
                        "credits": 3,
                        "cost": 0.00027
                      }
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  },
                  "schedule": {
                    "calendar": {
                      "times_of_day": [
                        "09:00",
                        "18:00"
                      ],
                      "cadence": {
                        "weekly": {
                          "days": [
                            "mon",
                            "wed",
                            "fri"
                          ]
                        }
                      }
                    },
                    "timezone": "Europe/Berlin"
                  },
                  "schedule_state": "active",
                  "next_scheduled_run": "2026-10-16T07:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/schedule/state": {
      "post": {
        "operationId": "setBatchScheduleState",
        "summary": "Pause or resume a schedule",
        "description": "Turn a scheduled job's future runs off or on without deleting its schedule. Separate from pausing a run (pauseBatchRun).",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "schedule_state"
                ],
                "properties": {
                  "schedule_state": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused"
                    ]
                  }
                }
              },
              "example": {
                "schedule_state": "paused"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job with its new `schedule_state`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                  "type": "scheduled",
                  "status": "closed",
                  "format": "markdown",
                  "zenrows_params": {
                    "response_type": "markdown"
                  },
                  "created_at": "2026-10-08T14:55:52Z",
                  "updated_at": "2026-10-08T14:55:52Z",
                  "latest_run": {
                    "run_id": "01M4E06YS7VZPY4G25DV6FR3B8",
                    "job_id": "01M4E06YS7BDRECVN5QRHJA6HR",
                    "run_sequence": 1,
                    "status": "completed",
                    "trigger": "manual",
                    "last_batch_received": false,
                    "stats": {
                      "total": 3,
                      "completed": 3,
                      "successful": 3,
                      "failed": 0,
                      "spend": {
                        "credits": 3,
                        "cost": 0.00027
                      }
                    },
                    "created_at": "2026-10-08T14:55:52Z",
                    "updated_at": "2026-10-08T14:56:06Z"
                  },
                  "schedule": {
                    "calendar": {
                      "times_of_day": [
                        "09:00",
                        "18:00"
                      ],
                      "cadence": {
                        "weekly": {
                          "days": [
                            "mon",
                            "wed",
                            "fri"
                          ]
                        }
                      }
                    },
                    "timezone": "Europe/Berlin"
                  },
                  "schedule_state": "paused",
                  "next_scheduled_run": "2026-10-16T07:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}/webhook": {
      "get": {
        "operationId": "getBatchWebhook",
        "summary": "Read a job's webhook",
        "description": "The webhook set on the job, if any.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job's webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchWebhook"
                },
                "example": {
                  "url": "https://your-app.com/webhooks/zenrows",
                  "signature": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "putBatchWebhook",
        "summary": "Set a job's webhook",
        "description": "Be notified when a run ends (`run.completed`, `run.failed`) instead of polling. Deliveries are at least once: dedupe on the `X-ZenRows-Event-Id` header. With `signature`, each delivery carries `X-Signature: t=<unix>,v1=<hex>,kid=<kid>`, an HMAC-SHA256 of `<t>.<raw body>` with your key (see listHmacKeys).",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchWebhook"
              },
              "example": {
                "url": "https://your-app.com/webhooks/zenrows",
                "signature": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The stored webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchWebhook"
                },
                "example": {
                  "url": "https://your-app.com/webhooks/zenrows",
                  "signature": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteBatchWebhook",
        "summary": "Remove a job's webhook",
        "description": "Stop delivering this job's notifications.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier returned when the job was created.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The webhook was removed."
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/job_inputs": {
      "post": {
        "operationId": "uploadBatchInput",
        "summary": "Upload a CSV of URLs",
        "description": "Reserve an upload for a CSV too large to send inline (up to 50 MB and 100,000 rows; the slot lives 24 hours). Then PUT the raw file to `upload.url` with `upload.headers`, and pass `file_input_id` to createBatchJob.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "csv"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "csv"
                    ]
                  },
                  "csv": {
                    "type": "object",
                    "required": [
                      "fields"
                    ],
                    "properties": {
                      "header": {
                        "type": "boolean",
                        "description": "`true` maps `fields` by header name; otherwise by 0-based column index."
                      },
                      "fields": {
                        "type": "object",
                        "required": [
                          "url"
                        ],
                        "properties": {
                          "url": {
                            "type": [
                              "string",
                              "integer"
                            ],
                            "description": "Header name or column index of the URL."
                          },
                          "external_id": {
                            "type": [
                              "string",
                              "integer"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "type": "csv",
                "csv": {
                  "header": true,
                  "fields": {
                    "url": "URL",
                    "external_id": "Customer Ref"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The upload slot.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "file_input_id": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "upload": {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Presigned URL to PUT the file to."
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "PUT"
                          ]
                        },
                        "headers": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "string"
                          },
                          "description": "Send exactly these headers with the upload."
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "file_input_id": "fi_01M4F4B8D3E2C1A9",
                  "expires_at": "2026-10-09T15:10:00Z",
                  "upload": {
                    "url": "https://inputs.example-bucket.s3.amazonaws.com/fi_01M4F4B8D3E2C1A9.csv?X-Amz-Expires=3600",
                    "method": "PUT",
                    "headers": {
                      "Content-Type": "text/csv"
                    },
                    "expires_at": "2026-10-08T16:10:00Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/webhook/test": {
      "post": {
        "operationId": "testWebhook",
        "summary": "Send a test webhook",
        "description": "Deliver a sample notification to your endpoint so you can check the receiver and, with `signature`, your signature verification before a real run.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchWebhook"
              },
              "example": {
                "url": "https://your-app.com/webhooks/zenrows",
                "signature": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The delivery attempt and its outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "delivered": {
                      "type": "boolean"
                    },
                    "status_code": {
                      "type": "integer",
                      "description": "Your receiver's HTTP status."
                    },
                    "elapsed_ms": {
                      "type": "integer"
                    },
                    "event_id": {
                      "type": "string"
                    },
                    "error": {
                      "type": "string",
                      "description": "Why the delivery failed, when it did."
                    }
                  }
                },
                "example": {
                  "delivered": true,
                  "status_code": 200,
                  "elapsed_ms": 184,
                  "event_id": "evt_01M4F5C9E4F3D2B1"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/hmac/keys": {
      "get": {
        "operationId": "listHmacKeys",
        "summary": "List webhook signing keys",
        "description": "Metadata of the HMAC keys your webhooks are signed with, never the secrets. An account with no key answers an empty object.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The account's signing keys.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Documented at https://docs.zenrows.com/batch/developer-guide-restapi.",
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/hmac/keys/rotate": {
      "post": {
        "operationId": "startHmacKeyRotation",
        "summary": "Start a key rotation",
        "description": "Create the account's first signing key, or stage a candidate next to the active one so you can accept both while you deploy. The secret is returned once: store it.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The new key and its secret.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "kid": {
                      "type": "string",
                      "description": "Key ID, sent as `kid` in `X-Signature`."
                    },
                    "secret": {
                      "type": "string",
                      "description": "Base64. Returned only once."
                    }
                  },
                  "additionalProperties": true
                },
                "example": {
                  "kid": "k_01M4F6D1F5A4E3C2",
                  "secret": "c2FtcGxlLXNlY3JldC1ub3QtcmVhbC0wMTIzNDU2Nzg5"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "cancelHmacKeyRotation",
        "summary": "Cancel a key rotation",
        "description": "Discard the staged candidate and keep signing with the active key.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "204": {
            "description": "The pending rotation was cancelled."
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/hmac/keys/rotate/finalize": {
      "post": {
        "operationId": "finalizeHmacKeyRotation",
        "summary": "Finish a key rotation",
        "description": "Promote the candidate to active and retire the previous key.",
        "tags": [
          "Batch"
        ],
        "servers": [
          {
            "url": "https://async.api.zenrows.com/v1",
            "description": "Batch (asynchronous jobs)"
          }
        ],
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "The active key after rotation.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Documented at https://docs.zenrows.com/batch/developer-guide-restapi.",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_argument`: validation failed. `invalid_tasks` lists each rejected task as `{index, reason}`. Documented at https://docs.zenrows.com/batch/developer-guide-restapi#error-handling-reference.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_argument",
                  "detail": "Validation failed.",
                  "instance": "/v1",
                  "status": 400,
                  "title": "Validation failed (invalid_argument)",
                  "type": "https://docs.zenrows.com/api-error-codes#invalid_argument"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: the `X-API-Key` header is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unauthenticated",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Unauthenticated (unauthenticated)",
                  "type": "https://docs.zenrows.com/api-error-codes#unauthenticated"
                }
              }
            }
          },
          "402": {
            "description": "`payment_required` (no credits left) or `api_key_cap_reached` (the key hit a credit cap; `detail` names the cap and when it resets).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "payment_required",
                  "detail": "No credits available.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "No credits available (payment_required)",
                  "type": "https://docs.zenrows.com/api-error-codes#payment_required"
                }
              }
            }
          },
          "429": {
            "description": "`quota_exceeded`: the account already runs its active jobs (3 by default, shared with Crawl). Wait for one to end.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "quota_exceeded",
                  "detail": "Too many active jobs.",
                  "instance": "/v1",
                  "status": 429,
                  "title": "Too many active jobs (quota_exceeded)",
                  "type": "https://docs.zenrows.com/api-error-codes#quota_exceeded"
                }
              }
            }
          },
          "503": {
            "description": "`internal`: a transient failure. Retry with backoff; for createBatchJob, list your jobs first, since the job may have been created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal",
                  "detail": "Temporary failure, retry with backoff.",
                  "instance": "/v1",
                  "status": 503,
                  "title": "Temporary failure, retry with backoff (internal)",
                  "type": "https://docs.zenrows.com/api-error-codes#internal"
                }
              }
            }
          }
        }
      }
    },
    "/crawls": {
      "post": {
        "operationId": "startCrawl",
        "summary": "Start a crawl",
        "description": "Start a crawl from one URL and return at once with `202 Accepted`, the crawl in the body and its path in the `Location` header. Each page it opens is one Fetch request with Adaptive Stealth Mode, billed 1 to 25 credits; failed pages are not billed. Documented at https://docs.zenrows.com/crawl/endpoints#start-a-crawl.",
        "tags": [
          "Crawl"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Makes a retry safe: a retry with the same key and body returns the same crawl and starts no second one. The same key with a different body is `422 idempotency_key_reused`.",
            "example": "catalog-2026-10-09"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "additionalProperties": false,
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048,
                    "description": "The start URL: a public `http` or `https` URL. The crawl starts on this exact URL and stays on its domain, subdomains included."
                  },
                  "depth": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100000,
                    "description": "How many link steps to follow from the start URL. At `1`, the links on the start page. Omit it to follow links until `max_items` or `max_pages` stops the crawl."
                  },
                  "max_items": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100000,
                    "default": 100,
                    "description": "Stop after keeping this many URLs."
                  },
                  "max_pages": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100000,
                    "default": 100,
                    "description": "Stop after fetching this many pages. Caps what the crawl costs. If both limits are reached together, `stop_reason` is `max_pages`."
                  },
                  "include_patterns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Keep, and open, only URLs that contain at least one of these texts, such as `/product/`. The start URL is never returned."
                  },
                  "exclude_patterns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Drop URLs that contain any of these texts, even when they match an include pattern."
                  },
                  "output_format": {
                    "type": "string",
                    "enum": [
                      "html"
                    ],
                    "description": "`html` also returns the HTML of each kept page. Omit it to get URLs only."
                  }
                }
              },
              "example": {
                "url": "https://www.scrapingcourse.com/ecommerce/",
                "max_pages": 10,
                "include_patterns": [
                  "/product/"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The crawl started.",
            "headers": {
              "Location": {
                "description": "The crawl's path.",
                "schema": {
                  "type": "string",
                  "example": "/v1/crawls/c_01M3XP7RZD4JT88F7PNPGBFRAF"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Crawl"
                },
                "example": {
                  "crawl_id": "c_01M3XP7RZD4JT88F7PNPGBFRAF",
                  "status": "running",
                  "url": "https://www.scrapingcourse.com/ecommerce/",
                  "max_items": 100,
                  "max_pages": 10,
                  "include_patterns": [
                    "/product/"
                  ],
                  "exclude_patterns": [],
                  "discovery": [
                    "links"
                  ],
                  "coverage": {
                    "pages_fetched": 0,
                    "pages_failed": 0,
                    "items_found": 0
                  },
                  "duplicates_removed": 0,
                  "created_at": "2026-10-09T09:00:12Z",
                  "results": [],
                  "next_cursor": "cur_Y18wMU0zWFA3UlpENEpUODhGN1BOUEdCRlJBRjow"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_request` (the body is not valid JSON, or the `Idempotency-Key` is over 255 characters), `unknown_parameter` (`detail` names it) or `invalid_parameter`. Documented at https://docs.zenrows.com/crawl/endpoints#errors.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unknown_parameter",
                  "title": "Unknown parameter",
                  "detail": "The request has a parameter this endpoint does not accept: max_depth.",
                  "status": 400,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "409": {
            "description": "`idempotency_request_in_flight`: a request with this `Idempotency-Key` is still in progress. Retry when it ends.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "idempotency_request_in_flight",
                  "title": "Request in flight",
                  "detail": "A request with this Idempotency-Key is still in progress. Retry when it ends.",
                  "status": 409,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "422": {
            "description": "`invalid_start_url` (the host is an IP address or a private address, or the URL is over 2,048 characters), `invalid_parameter` or `idempotency_key_reused`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_start_url",
                  "title": "Invalid start URL",
                  "detail": "The start URL must be a public http or https URL.",
                  "status": 422,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_crawls`: the account already runs its active jobs (3 by default, shared with Batch). Wait for one to end; the response carries `Retry-After: 30`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "too_many_crawls",
                  "title": "Too many active crawls",
                  "detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
                  "status": 429,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: something failed on our side. Retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal_error",
                  "title": "Internal error",
                  "detail": "Something failed on our side. Retry later.",
                  "status": 500,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listCrawls",
        "summary": "List your crawls",
        "description": "Your crawls, newest first, without their results. Documented at https://docs.zenrows.com/crawl/endpoints#list-your-crawls.",
        "tags": [
          "Crawl"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many crawls to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of crawls. `next_cursor` is absent on the last page.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "crawls": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CrawlSummary"
                      }
                    },
                    "next_cursor": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "crawls": [
                    {
                      "crawl_id": "c_01M3XP7RZD4JT88F7PNPGBFRAF",
                      "status": "completed",
                      "stop_reason": "max_pages",
                      "url": "https://www.scrapingcourse.com/ecommerce/",
                      "max_items": 100,
                      "max_pages": 10,
                      "include_patterns": [
                        "/product/"
                      ],
                      "exclude_patterns": [],
                      "discovery": [
                        "links"
                      ],
                      "coverage": {
                        "pages_fetched": 10,
                        "pages_failed": 0,
                        "items_found": 88
                      },
                      "duplicates_removed": 412,
                      "created_at": "2026-10-09T09:00:12Z",
                      "finished_at": "2026-10-09T09:00:41Z"
                    }
                  ],
                  "next_cursor": "eyJjcmF3bF9pZCI6ImNfMDFNM1hQN1JaRDRKVDg4RjdQTlBHQkZSQUYifQ"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_request`: `limit` or `cursor` is not valid. Documented at https://docs.zenrows.com/crawl/endpoints#errors.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_request",
                  "title": "Invalid request",
                  "detail": "limit must be between 1 and 100.",
                  "status": 400,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_crawls`: the account already runs its active jobs (3 by default, shared with Batch). Wait for one to end; the response carries `Retry-After: 30`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "too_many_crawls",
                  "title": "Too many active crawls",
                  "detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
                  "status": 429,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: something failed on our side. Retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal_error",
                  "title": "Internal error",
                  "detail": "Something failed on our side. Retry later.",
                  "status": 500,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          }
        }
      }
    },
    "/crawls/{crawl_id}": {
      "get": {
        "operationId": "getCrawl",
        "summary": "Read a crawl and its results",
        "description": "The crawl, its coverage so far and one page of results. While it runs, `next_cursor` is never `null`: read again with the same cursor to get only the new URLs. Each URL is returned once. Documented at https://docs.zenrows.com/crawl/endpoints#read-a-crawl.",
        "tags": [
          "Crawl"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "crawl_id",
            "in": "path",
            "required": true,
            "description": "The crawl's ID, as returned when it started.",
            "schema": {
              "type": "string"
            },
            "example": "c_01M3XP7RZD4JT88F7PNPGBFRAF"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` from the previous read. Omit it to start from the first result.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many results to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The crawl and a page of its results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Crawl"
                },
                "example": {
                  "crawl_id": "c_01M3XP7RZD4JT88F7PNPGBFRAF",
                  "status": "completed",
                  "stop_reason": "max_pages",
                  "url": "https://www.scrapingcourse.com/ecommerce/",
                  "max_items": 100,
                  "max_pages": 10,
                  "include_patterns": [
                    "/product/"
                  ],
                  "exclude_patterns": [],
                  "discovery": [
                    "links"
                  ],
                  "coverage": {
                    "pages_fetched": 10,
                    "pages_failed": 0,
                    "items_found": 88
                  },
                  "duplicates_removed": 412,
                  "created_at": "2026-10-09T09:00:12Z",
                  "finished_at": "2026-10-09T09:00:41Z",
                  "results": [
                    {
                      "url": "https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/"
                    },
                    {
                      "url": "https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "`invalid_cursor` (the cursor belongs to another crawl) or `invalid_request` (`limit` is not valid). Documented at https://docs.zenrows.com/crawl/endpoints#errors.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_cursor",
                  "title": "Invalid cursor",
                  "detail": "The cursor does not belong to this crawl.",
                  "status": 400,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "404": {
            "description": "`crawl_not_found`: no crawl with this ID exists on your account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "crawl_not_found",
                  "title": "Crawl not found",
                  "detail": "No crawl with this identifier exists for this account.",
                  "status": 404,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_crawls`: the account already runs its active jobs (3 by default, shared with Batch). Wait for one to end; the response carries `Retry-After: 30`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "too_many_crawls",
                  "title": "Too many active crawls",
                  "detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
                  "status": 429,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: something failed on our side. Retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal_error",
                  "title": "Internal error",
                  "detail": "Something failed on our side. Retry later.",
                  "status": 500,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          }
        }
      }
    },
    "/crawls/{crawl_id}/download": {
      "get": {
        "operationId": "downloadCrawl",
        "summary": "Download all results",
        "description": "Every result as one NDJSON file named `{crawl_id}.jsonl`, one JSON object per line. Each line has the `url`; with `output_format`, also `content_status` and, once fetched, the page HTML in `content`. While the crawl runs, a later download may hold more lines. Documented at https://docs.zenrows.com/crawl/endpoints#download-the-results.",
        "tags": [
          "Crawl"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "crawl_id",
            "in": "path",
            "required": true,
            "description": "The crawl's ID, as returned when it started.",
            "schema": {
              "type": "string"
            },
            "example": "c_01M3XP7RZD4JT88F7PNPGBFRAF"
          }
        ],
        "responses": {
          "200": {
            "description": "The results as NDJSON.",
            "headers": {
              "X-Crawl-Status": {
                "description": "The crawl's status when the file was produced. After a stop it reads `stopped`, yet a later download may hold more lines for up to 10 minutes.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "running",
                    "completed",
                    "stopped",
                    "failed"
                  ]
                }
              }
            },
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "string"
                },
                "example": "{\"url\":\"https://www.scrapingcourse.com/ecommerce/product/abominable-hoodie/\"}\n{\"url\":\"https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/\"}\n"
              }
            }
          },
          "400": {
            "description": "`unknown_parameter`: the request has a query parameter this endpoint does not accept; `detail` names it. Documented at https://docs.zenrows.com/crawl/endpoints#errors.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unknown_parameter",
                  "title": "Unknown parameter",
                  "detail": "The request has a parameter this endpoint does not accept: limit.",
                  "status": 400,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "404": {
            "description": "`crawl_not_found`: no crawl with this ID exists on your account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "crawl_not_found",
                  "title": "Crawl not found",
                  "detail": "No crawl with this identifier exists for this account.",
                  "status": 404,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_crawls`: the account already runs its active jobs (3 by default, shared with Batch). Wait for one to end; the response carries `Retry-After: 30`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "too_many_crawls",
                  "title": "Too many active crawls",
                  "detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
                  "status": 429,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: something failed on our side. Retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal_error",
                  "title": "Internal error",
                  "detail": "Something failed on our side. Retry later.",
                  "status": 500,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          }
        }
      }
    },
    "/crawls/{crawl_id}/contents/{content_id}": {
      "get": {
        "operationId": "getCrawlContent",
        "summary": "Read one page's HTML",
        "description": "The HTML of one kept page, for a crawl started with `output_format`. Take the path from the result's `content_url`. Documented at https://docs.zenrows.com/crawl/endpoints#read-a-page.",
        "tags": [
          "Crawl"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "crawl_id",
            "in": "path",
            "required": true,
            "description": "The crawl's ID, as returned when it started.",
            "schema": {
              "type": "string"
            },
            "example": "c_01M3XP7RZD4JT88F7PNPGBFRAF"
          },
          {
            "name": "content_id",
            "in": "path",
            "required": true,
            "description": "From the result's `content_url`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "download",
            "in": "query",
            "required": false,
            "description": "`true` returns the page as a file to save.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The page's HTML.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<!doctype html>\n<html lang=\"en-US\">\n<head><title>Abominable Hoodie</title></head>\n<body>...</body>\n</html>"
              }
            }
          },
          "400": {
            "description": "`unknown_parameter`: the request has a query parameter this endpoint does not accept; `detail` names it. Documented at https://docs.zenrows.com/crawl/endpoints#errors.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unknown_parameter",
                  "title": "Unknown parameter",
                  "detail": "The request has a parameter this endpoint does not accept: limit.",
                  "status": 400,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "404": {
            "description": "`crawl_not_found`, or `content_not_found`: the page is not fetched yet, its fetch failed, or the crawl has no `output_format`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "content_not_found",
                  "title": "Content not found",
                  "detail": "This page has not been fetched yet.",
                  "status": 404,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_crawls`: the account already runs its active jobs (3 by default, shared with Batch). Wait for one to end; the response carries `Retry-After: 30`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "too_many_crawls",
                  "title": "Too many active crawls",
                  "detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
                  "status": 429,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: something failed on our side. Retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal_error",
                  "title": "Internal error",
                  "detail": "Something failed on our side. Retry later.",
                  "status": 500,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          }
        }
      }
    },
    "/crawls/{crawl_id}/stop": {
      "post": {
        "operationId": "stopCrawl",
        "summary": "Stop a crawl",
        "description": "Stop a running crawl. No new page is fetched; pages already being fetched finish, are billed and are kept for up to 10 minutes. Read the crawl until `next_cursor` is `null` for its final results. A crawl that already ended returns its final state. Send no body. Documented at https://docs.zenrows.com/crawl/endpoints#stop-a-crawl.",
        "tags": [
          "Crawl"
        ],
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "crawl_id",
            "in": "path",
            "required": true,
            "description": "The crawl's ID, as returned when it started.",
            "schema": {
              "type": "string"
            },
            "example": "c_01M3XP7RZD4JT88F7PNPGBFRAF"
          }
        ],
        "responses": {
          "200": {
            "description": "The crawl, stopped.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "crawl_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "stop_reason": {
                      "type": "string"
                    },
                    "finished_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "crawl_id": "c_01M3XP7RZD4JT88F7PNPGBFRAF",
                  "status": "stopped",
                  "stop_reason": "user",
                  "finished_at": "2026-10-09T09:01:30Z"
                }
              }
            }
          },
          "400": {
            "description": "`unknown_parameter`: the request has a query parameter this endpoint does not accept; `detail` names it. Documented at https://docs.zenrows.com/crawl/endpoints#errors.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "unknown_parameter",
                  "title": "Unknown parameter",
                  "detail": "The request has a parameter this endpoint does not accept: limit.",
                  "status": 400,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH002",
                  "detail": "Invalid API key.",
                  "instance": "/v1",
                  "status": 401,
                  "title": "Invalid apikey provided (AUTH002)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH002"
                }
              }
            }
          },
          "402": {
            "description": "The account is out of credits, or the plan does not include this capability.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "AUTH004",
                  "detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
                  "instance": "/v1",
                  "status": 402,
                  "title": "Usage exceeded (AUTH004)",
                  "type": "https://docs.zenrows.com/api-error-codes#AUTH004"
                }
              }
            }
          },
          "404": {
            "description": "`crawl_not_found`: no crawl with this ID exists on your account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "crawl_not_found",
                  "title": "Crawl not found",
                  "detail": "No crawl with this identifier exists for this account.",
                  "status": 404,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_crawls`: the account already runs its active jobs (3 by default, shared with Batch). Wait for one to end; the response carries `Retry-After: 30`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "too_many_crawls",
                  "title": "Too many active crawls",
                  "detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
                  "status": 429,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: something failed on our side. Retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "internal_error",
                  "title": "Internal error",
                  "detail": "Something failed on our side. Retry later.",
                  "status": 500,
                  "instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "ConcurrencyLimit": {
        "description": "Concurrent requests this plan allows. The rate limit, in the unit Zenrows meters: slots in flight, not requests per interval.",
        "schema": {
          "type": "integer",
          "example": 20
        }
      },
      "ConcurrencyRemaining": {
        "description": "Free slots at the moment the request was received. Zero means the next request is refused with 429 until one finishes.",
        "schema": {
          "type": "integer",
          "example": 17
        }
      },
      "XRequestCost": {
        "description": "Cost of this request in US dollars at your plan's price per credit, so it varies with the features the request enabled. `0` when the request is not charged. For the number of credits, read `X-Request-Credits`.",
        "schema": {
          "type": "number",
          "example": 0.001
        }
      },
      "XRequestCredits": {
        "description": "Credits charged for this request. Requests that fail, and Extract refusals such as `REQS007`, `no_data_extracted` and `blocked_document`, are not charged.",
        "schema": {
          "type": "integer",
          "example": 5
        }
      },
      "XRequestId": {
        "description": "Identifier for this request. Quote it when reporting a problem.",
        "schema": {
          "type": "string",
          "example": "67fa4e35647515d8ad61bb3ee041e1bb"
        }
      },
      "RateLimitPolicy": {
        "description": "The standing rule, as a structured field: `\"signup\";q=3;w=86400` is three signups per client IP per 24 hours. Admin-editable, so read it rather than assuming three.",
        "schema": {
          "type": "string",
          "example": "\"signup\";q=3;w=86400"
        }
      },
      "RateLimit": {
        "description": "Where this caller stands: `r` is signups left, `t` is seconds until one frees. `t` counts from the oldest signup still inside the window, so it is a real wait, not the window length restated.",
        "schema": {
          "type": "string",
          "example": "\"signup\";r=1;t=52341"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before signing up again. Present only when nothing is left.",
        "schema": {
          "type": "integer",
          "example": 52341
        }
      }
    },
    "securitySchemes": {
      "apiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "apikey",
        "description": "Fetch, Extract, Crawl and the account endpoint accept the key as the `apikey` query parameter. Keys are per account and self-serve: create one in the Zenrows dashboard (app.zenrows.com), or, for an agent with no human present, `POST https://app.zenrows.com/api/agent/signup`."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Batch, Crawl, the Extract endpoints and the account endpoint read the same key from the `X-API-Key` header."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Zenrows error envelope, sent as `application/problem+json` (RFC 9457 problem details). `code` is the stable identifier to branch on; `type` links to its entry in the catalogue at https://docs.zenrows.com/api-error-codes. Read back from live responses.",
        "properties": {
          "code": {
            "type": "string",
            "example": "AUTH002"
          },
          "status": {
            "type": "integer",
            "example": 401
          },
          "title": {
            "type": "string",
            "example": "Invalid apikey provided (AUTH002)"
          },
          "detail": {
            "type": "string",
            "example": "Invalid API key."
          },
          "type": {
            "type": "string",
            "format": "uri",
            "example": "https://docs.zenrows.com/api-error-codes#AUTH002"
          },
          "instance": {
            "type": "string",
            "description": "The request path or a request URN. Quote it when reporting a problem.",
            "example": "/v1"
          }
        }
      },
      "ExtractEndpointError": {
        "type": "object",
        "description": "Error shape of the Extract endpoints: lowercase `code` values, and `type` links to the code's entry in https://docs.zenrows.com/api-error-codes.",
        "properties": {
          "code": {
            "type": "string",
            "examples": [
              "invalid_argument",
              "not_found",
              "in_progress",
              "idempotency_conflict",
              "out_of_allowance"
            ]
          },
          "detail": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "description": "Machine-readable tag on `invalid_argument`, for example `invalid_domain`."
          },
          "status": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ExtractPreparation": {
        "type": "object",
        "description": "A domain's preparation for Extract.",
        "properties": {
          "domain": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "preparing",
              "ready",
              "failed"
            ],
            "description": "Whether the domain can be used yet. Branch on this."
          },
          "state": {
            "type": "string",
            "description": "The current step. Gains steps over time.",
            "examples": [
              "received",
              "discovering",
              "preparing",
              "verifying",
              "ready",
              "failed"
            ]
          },
          "roles": {
            "type": "array",
            "description": "Progress per page, with its page type in `role`. Only present for the account that submitted the domain.",
            "items": {
              "type": "object",
              "properties": {
                "role": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "detail": {
                  "type": "string",
                  "description": "Why this page stopped, when it did."
                }
              }
            }
          },
          "failure": {
            "type": "object",
            "description": "Present when `status` is `failed`.",
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "interrupted",
                  "preparation_exhausted",
                  "discovery_failed",
                  "unpreparable",
                  "preparation_failed",
                  "verification_failed",
                  "unsupported"
                ]
              },
              "detail": {
                "type": "string"
              },
              "slot_consumed": {
                "type": "boolean",
                "description": "Whether the attempt used an allowance slot."
              }
            }
          },
          "submitted_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SignupError": {
        "type": "object",
        "description": "The onboarding surface has its own error shape, flatter than the API's envelope. Branch on `error`.",
        "properties": {
          "error": {
            "type": "string",
            "examples": [
              "challenge_required",
              "challenge_locked",
              "rate_limited",
              "signup_disabled",
              "signup_failed",
              "invalid_key"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Job": {
        "type": "object",
        "description": "A batch job and the state of its most recent run.",
        "properties": {
          "job_id": {
            "type": "string",
            "description": "Identifier to poll and to collect results with."
          },
          "name": {
            "type": "string"
          },
          "external_id": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "type": {
            "type": "string",
            "enum": [
              "regular",
              "scheduled"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed",
              "deleted"
            ],
            "description": "Whether the job still accepts new tasks; `deleted` while a deletion completes."
          },
          "format": {
            "type": "string",
            "description": "The content format the tasks return, from `zenrows_params`.",
            "examples": [
              "html",
              "markdown",
              "plaintext",
              "json",
              "pdf"
            ]
          },
          "zenrows_params": {
            "type": "object",
            "additionalProperties": true,
            "description": "The Fetch parameters applied to every task."
          },
          "schedule": {
            "$ref": "#/components/schemas/BatchSchedule"
          },
          "schedule_state": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "description": "Scheduled jobs only."
          },
          "next_scheduled_run": {
            "type": "string",
            "format": "date-time",
            "description": "Scheduled jobs only."
          },
          "webhook": {
            "$ref": "#/components/schemas/BatchWebhook"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "latest_run": {
            "$ref": "#/components/schemas/Run"
          }
        }
      },
      "Run": {
        "type": "object",
        "description": "One run of a job.",
        "properties": {
          "run_id": {
            "type": "string"
          },
          "job_id": {
            "type": "string"
          },
          "run_sequence": {
            "type": "integer",
            "description": "1 for the first run, then one more per rerun or scheduled fire."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "stopped",
              "deleted"
            ],
            "description": "`completed`, `failed`, `stopped` and `deleted` are terminal."
          },
          "pause_state": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "description": "`paused` after pauseBatchRun; `status` does not change."
          },
          "trigger": {
            "type": "string",
            "enum": [
              "manual",
              "scheduled"
            ],
            "description": "What started the run."
          },
          "last_batch_received": {
            "type": "boolean",
            "description": "Open jobs: whether the final addBatchTasks call arrived."
          },
          "stats": {
            "type": "object",
            "description": "Task counters. `completed` is `successful` plus `failed`.",
            "properties": {
              "total": {
                "type": "integer"
              },
              "completed": {
                "type": "integer"
              },
              "successful": {
                "type": "integer"
              },
              "failed": {
                "type": "integer"
              },
              "spend": {
                "type": "object",
                "description": "Absent until there is spend.",
                "properties": {
                  "credits": {
                    "type": "integer"
                  },
                  "cost": {
                    "type": "number",
                    "description": "US dollars."
                  }
                }
              }
            }
          },
          "failure_reason": {
            "type": "string",
            "description": "Only when the whole run failed. Open set; new values may appear.",
            "examples": [
              "insufficient_credits",
              "subscription_inactive",
              "api_key_cap_reached"
            ]
          },
          "failure_detail": {
            "type": "string",
            "description": "What happened, for example which cap and when it resets."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "JobSubmitted": {
        "type": "object",
        "description": "The answer to createBatchJob.",
        "properties": {
          "job_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "accepted_tasks": {
            "type": "integer"
          },
          "webhook": {
            "$ref": "#/components/schemas/BatchWebhook"
          },
          "latest_run": {
            "$ref": "#/components/schemas/Run"
          }
        }
      },
      "BatchTask": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "external_id": {
            "type": "string",
            "description": "Your own identifier, echoed on the result. Need not be unique."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Your own data, echoed on the result."
          },
          "zenrows_params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Overrides the job-level parameters for this URL."
          },
          "method": {
            "type": "string",
            "enum": [
              "GET",
              "POST"
            ],
            "default": "GET",
            "description": "`POST` sends `body` to the target."
          },
          "body": {
            "type": "string",
            "maxLength": 16384,
            "description": "Sent to the target as is, with `method: POST`. Up to 16 KiB."
          }
        }
      },
      "BatchSchedule": {
        "type": "object",
        "description": "Exactly one of `at`, `rate` or `calendar`, plus `timezone` for `at` and `calendar`. Times of day are full hours; runs are at least 60 minutes apart.",
        "properties": {
          "at": {
            "type": "object",
            "additionalProperties": true,
            "description": "One run at a single wall-clock time."
          },
          "rate": {
            "type": "object",
            "description": "Every N hours.",
            "properties": {
              "every": {
                "type": "integer",
                "minimum": 1
              },
              "unit": {
                "type": "string",
                "enum": [
                  "hour"
                ]
              }
            }
          },
          "calendar": {
            "type": "object",
            "properties": {
              "times_of_day": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[0-2][0-9]:00$"
                },
                "description": "Full hours, `HH:00`."
              },
              "cadence": {
                "type": "object",
                "additionalProperties": true,
                "description": "For example `{\"weekly\": {\"days\": [\"mon\", \"wed\", \"fri\"]}}`."
              }
            }
          },
          "timezone": {
            "type": "string",
            "description": "IANA name, for example `Europe/Berlin`."
          }
        }
      },
      "BatchWebhook": {
        "type": "object",
        "required": [
          "url"
        ],
        "description": "Where run notifications (`run.completed`, `run.failed`) are delivered.",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Your HTTPS receiver."
          },
          "signature": {
            "type": "boolean",
            "description": "Sign deliveries with your HMAC key (needs an active key, see startHmacKeyRotation)."
          }
        }
      },
      "TaskResult": {
        "type": "object",
        "description": "One URL's outcome in a run. A failed task is a row with `error`, not an HTTP error.",
        "properties": {
          "task_id": {
            "type": "string"
          },
          "run_id": {
            "type": "string"
          },
          "source_run_id": {
            "type": "string",
            "description": "On a rerun, the run a carried-over result came from."
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "external_id": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "status": {
            "type": "string",
            "enum": [
              "successful",
              "failed",
              "pending",
              "processing"
            ]
          },
          "type": {
            "type": "string",
            "description": "The stored content's format.",
            "examples": [
              "html",
              "markdown",
              "json"
            ]
          },
          "result_url": {
            "type": "string",
            "format": "uri",
            "description": "Presigned link to the stored content, valid for 2 hours."
          },
          "error": {
            "type": "object",
            "description": "On failed rows, a problem object. `code` is a hint, not a contract.",
            "properties": {
              "type": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "status": {
                "type": "integer"
              },
              "detail": {
                "type": "string"
              },
              "code": {
                "type": "string"
              },
              "instance": {
                "type": "string"
              }
            }
          },
          "spend": {
            "type": "object",
            "description": "Credits this task cost.",
            "properties": {
              "total": {
                "type": "object",
                "description": "Across all attempts.",
                "properties": {
                  "credits": {
                    "type": "integer"
                  },
                  "cost": {
                    "type": "number"
                  }
                }
              },
              "last_attempt": {
                "type": "object",
                "properties": {
                  "credits": {
                    "type": "integer"
                  },
                  "cost": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Read back from live responses."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Crawl": {
        "type": "object",
        "description": "A crawl, its coverage so far and one page of results.",
        "properties": {
          "crawl_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "completed",
              "stopped",
              "failed"
            ],
            "description": "`completed`: nothing was left to open, or a limit was reached (see `stop_reason`). `stopped`: you stopped it. `failed`: see `error`."
          },
          "stop_reason": {
            "type": "string",
            "enum": [
              "max_items",
              "max_pages",
              "user"
            ],
            "description": "Why the crawl ended early. Absent when nothing was left to open, and when the crawl failed."
          },
          "error": {
            "type": "object",
            "description": "Present only when `status` is `failed`. Older crawls can carry `domain_not_allowed` (the domain was not prepared for Extract).",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "seed_unreachable",
                  "no_items_found",
                  "insufficient_credits",
                  "internal_error",
                  "domain_not_allowed"
                ]
              },
              "detail": {
                "type": "string"
              }
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "The start URL: a public `http` or `https` URL. The crawl starts on this exact URL and stays on its domain, subdomains included."
          },
          "depth": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "description": "How many link steps to follow from the start URL. At `1`, the links on the start page. Omit it to follow links until `max_items` or `max_pages` stops the crawl."
          },
          "max_items": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 100,
            "description": "Stop after keeping this many URLs."
          },
          "max_pages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 100,
            "description": "Stop after fetching this many pages. Caps what the crawl costs. If both limits are reached together, `stop_reason` is `max_pages`."
          },
          "include_patterns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keep, and open, only URLs that contain at least one of these texts, such as `/product/`. The start URL is never returned."
          },
          "exclude_patterns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Drop URLs that contain any of these texts, even when they match an include pattern."
          },
          "output_format": {
            "type": "string",
            "enum": [
              "html"
            ],
            "description": "`html` also returns the HTML of each kept page. Omit it to get URLs only."
          },
          "discovery": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "links",
                "pagination"
              ]
            },
            "description": "`[\"links\"]`: the crawl follows the links in each page's HTML. Older crawls can also list `pagination`."
          },
          "coverage": {
            "type": "object",
            "properties": {
              "pages_fetched": {
                "type": "integer",
                "description": "Pages fetched so far, successful or not, at most `max_pages`."
              },
              "pages_failed": {
                "type": "integer",
                "description": "Pages that failed to load."
              },
              "items_found": {
                "type": "integer",
                "description": "URLs returned so far, after duplicates and patterns. At most `max_items`."
              }
            }
          },
          "duplicates_removed": {
            "type": "integer",
            "description": "Links met again and dropped. Results never hold a duplicate."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "description": "Absent while the crawl runs."
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URL the crawl found, normalized: scheme, `www.` and a trailing slash do not make two URLs, and tracking parameters such as `utm_*` are removed."
                },
                "content_status": {
                  "type": "string",
                  "enum": [
                    "pending",
                    "fetched",
                    "failed"
                  ],
                  "description": "With `output_format` only."
                },
                "content_url": {
                  "type": "string",
                  "description": "With `output_format` only, once fetched: the path to read the page."
                }
              }
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Send it as `cursor` on the next read. Never `null` while the crawl runs; `null` once it has ended and its last results were read."
          }
        }
      },
      "CrawlSummary": {
        "type": "object",
        "description": "A crawl and its coverage so far.",
        "properties": {
          "crawl_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "completed",
              "stopped",
              "failed"
            ],
            "description": "`completed`: nothing was left to open, or a limit was reached (see `stop_reason`). `stopped`: you stopped it. `failed`: see `error`."
          },
          "stop_reason": {
            "type": "string",
            "enum": [
              "max_items",
              "max_pages",
              "user"
            ],
            "description": "Why the crawl ended early. Absent when nothing was left to open, and when the crawl failed."
          },
          "error": {
            "type": "object",
            "description": "Present only when `status` is `failed`. Older crawls can carry `domain_not_allowed` (the domain was not prepared for Extract).",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "seed_unreachable",
                  "no_items_found",
                  "insufficient_credits",
                  "internal_error",
                  "domain_not_allowed"
                ]
              },
              "detail": {
                "type": "string"
              }
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "The start URL: a public `http` or `https` URL. The crawl starts on this exact URL and stays on its domain, subdomains included."
          },
          "depth": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "description": "How many link steps to follow from the start URL. At `1`, the links on the start page. Omit it to follow links until `max_items` or `max_pages` stops the crawl."
          },
          "max_items": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 100,
            "description": "Stop after keeping this many URLs."
          },
          "max_pages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 100,
            "description": "Stop after fetching this many pages. Caps what the crawl costs. If both limits are reached together, `stop_reason` is `max_pages`."
          },
          "include_patterns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keep, and open, only URLs that contain at least one of these texts, such as `/product/`. The start URL is never returned."
          },
          "exclude_patterns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Drop URLs that contain any of these texts, even when they match an include pattern."
          },
          "output_format": {
            "type": "string",
            "enum": [
              "html"
            ],
            "description": "`html` also returns the HTML of each kept page. Omit it to get URLs only."
          },
          "discovery": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "links",
                "pagination"
              ]
            },
            "description": "`[\"links\"]`: the crawl follows the links in each page's HTML. Older crawls can also list `pagination`."
          },
          "coverage": {
            "type": "object",
            "properties": {
              "pages_fetched": {
                "type": "integer",
                "description": "Pages fetched so far, successful or not, at most `max_pages`."
              },
              "pages_failed": {
                "type": "integer",
                "description": "Pages that failed to load."
              },
              "items_found": {
                "type": "integer",
                "description": "URLs returned so far, after duplicates and patterns. At most `max_items`."
              }
            }
          },
          "duplicates_removed": {
            "type": "integer",
            "description": "Links met again and dropped. Results never hold a duplicate."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "description": "Absent while the crawl runs."
          }
        }
      }
    }
  }
}
