{
  "openapi": "3.1.0",
  "info": {
    "title": "Prefetch API",
    "description": "Extract brand identity, company data, screenshots, IAB classifications, and clean page content from any URL.",
    "version": "1.0.0",
    "contact": {
      "email": "support@prefetch.io"
    }
  },
  "servers": [
    {
      "url": "https://api.prefetch.io",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Your Prefetch API key. Obtain one from the dashboard."
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "properties": {
          "requestId": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier for this request.",
            "example": "a3f2c1d4-7b6e-4f2a-9c1d-8e3f2a1b4c5d"
          },
          "durationMs": {
            "type": "integer",
            "nullable": true,
            "description": "Time taken to process the request in milliseconds.",
            "example": 1842
          }
        },
        "required": ["requestId", "durationMs"]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [false],
            "description": "Always false. Absent, like `meta`, on authentication and rate-limit errors, which are answered before a request is processed."
          },
          "error": {
            "type": "string",
            "description": "Human-readable error message. The wording can change: branch on `error_code`.",
            "example": "Credit limit exceeded"
          },
          "error_code": {
            "type": "string",
            "enum": ["INVALID_REQUEST", "PAYLOAD_TOO_LARGE", "NOT_FOUND", "CONFLICT", "UNAUTHORIZED", "FORBIDDEN", "CREDITS_EXHAUSTED", "RATE_LIMITED", "CONCURRENCY_LIMITED", "URL_BLOCKED", "URL_NOT_PERMITTED", "DNS_RESOLUTION_FAILED", "TARGET_BLOCKED", "TARGET_CONNECTION_FAILED", "TARGET_TIMEOUT", "TARGET_SSL_ERROR", "TARGET_SERVER_ERROR", "TARGET_CLIENT_ERROR", "TARGET_NOT_A_PAGE", "NO_LINKS_FOUND", "TARGET_UNLOADABLE", "RESEARCH_INCONCLUSIVE", "TIMEOUT", "SERVICE_BUSY", "SERVICE_UNAVAILABLE", "INTERNAL_ERROR"],
            "description": "What went wrong, for machines. Stable: a code keeps its meaning once published. See [Error handling](/concepts/errors).",
            "example": "CREDITS_EXHAUSTED"
          },
          "retryable": {
            "type": "boolean",
            "description": "Whether the same request can succeed if sent again after a short wait (honour `Retry-After` when present). False for problems with the request or the target.",
            "example": false
          },
          "retryAfterSeconds": {
            "type": "integer",
            "description": "On `RATE_LIMITED`: seconds until a request will be accepted."
          },
          "limit": {
            "type": "integer",
            "description": "On `CONCURRENCY_LIMITED`: how many requests this key may have in flight."
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": ["error", "error_code", "retryable"]
      },
      "CodeColorItem": {
        "type": "object",
        "description": "One color scraped from the page's CSS, HTML, or JavaScript.",
        "properties": {
          "color": {
            "type": "string",
            "description": "The raw value as written on the page.",
            "example": "#635bff"
          },
          "group": {
            "type": "string",
            "description": "Nearest named color, used as the group key.",
            "example": "blueviolet"
          },
          "distance": {
            "type": "number",
            "description": "Distance to that named color. 0 is an exact match.",
            "example": 0
          },
          "name": {
            "type": "string",
            "description": "Tint label within the group, ordered nearest-first.",
            "example": "blueviolet-100"
          }
        },
        "required": [
          "color",
          "group",
          "distance",
          "name"
        ]
      },
      "ColorItem": {
        "type": "object",
        "properties": {
          "color": {
            "type": "string",
            "description": "The color in `rgb()` form.",
            "example": "rgb(99, 91, 255)"
          },
          "hex": {
            "type": "string",
            "description": "The color as a hex triplet.",
            "example": "#635BFF"
          },
          "name": {
            "type": "string",
            "description": "A human-readable name for the color, such as `Medium Slate Blue` or `midnightblue`.",
            "example": "Medium Slate Blue"
          },
          "type": {
            "type": "string",
            "description": "How the brand uses the color, when known: `accent`, `brand`, `dark`, `light` or `background`.",
            "example": "accent"
          },
          "source": {
            "type": "string",
            "description": "Where the color came from. Present on `screenshot_colors` entries only.",
            "example": "screenshot"
          }
        },
        "required": [
          "color",
          "hex",
          "name"
        ]
      },
      "ColorsBlock": {
        "type": "object",
        "properties": {
          "brand_colors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ColorItem"
            },
            "description": "The brand palette, built from the logo and brand assets. Always present."
          },
          "code_colors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/CodeColorItem"
              }
            },
            "description": "Colors scraped from the page's code, keyed by nearest named color. Present only when `css=true`, `html=true`, or `javascript=true`. Sources are merged into one map, not split per source.",
            "example": {
              "blueviolet": [
                {
                  "color": "#635bff",
                  "group": "blueviolet",
                  "distance": 0,
                  "name": "blueviolet-100"
                }
              ]
            }
          },
          "screenshot_colors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ColorItem"
            },
            "description": "Dominant colors sampled from the screenshot. Present only when `screenshotColors=N` is passed."
          },
          "roles": {
            "type": "object",
            "properties": {
              "primary": {
                "type": "string",
                "nullable": true
              },
              "secondary": {
                "type": "string",
                "nullable": true
              },
              "background": {
                "type": "string",
                "nullable": true
              },
              "text": {
                "type": "string",
                "nullable": true
              },
              "link": {
                "type": "string",
                "nullable": true
              }
            },
            "required": ["primary", "secondary", "background", "text", "link"],
            "description": "The role each color plays on the page, read from its rendered styles: the primary and secondary button fills, the page background, body text and links. Hex, or null where the page gives no clear answer.",
            "example": {
              "primary": "#635BFF",
              "secondary": "#0A2540",
              "background": "#FFFFFF",
              "text": "#425466",
              "link": "#635BFF"
            }
          }
        },
        "required": [
          "brand_colors"
        ]
      },
      "BrandFonts": {
        "type": "object",
        "properties": {
          "families": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Font family names detected on the page.",
            "example": ["Inter", "Roboto"]
          }
        },
        "required": ["families"]
      },
      "LogoObject": {
        "type": "object",
        "nullable": true,
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Public URL to the logo asset.",
            "example": "https://cdn.example.com/logo.svg"
          },
          "width": {
            "type": "number",
            "nullable": true,
            "description": "Intrinsic width of the logo in pixels."
          },
          "height": {
            "type": "number",
            "nullable": true,
            "description": "Intrinsic height of the logo in pixels."
          },
          "type": {
            "type": "string",
            "description": "What the image is, when known, such as `logo`.",
            "example": "logo"
          },
          "format": {
            "type": "string",
            "description": "The image format, when known, such as `svg` or `png`.",
            "example": "svg"
          },
          "background": {
            "type": "string",
            "description": "The logo's background, when known, such as `transparent`.",
            "example": "transparent"
          }
        },
        "required": ["url"]
      },
      "LogosBlock": {
        "type": "object",
        "properties": {
          "primary": {
            "$ref": "#/components/schemas/LogoObject",
            "description": "Best candidate for the primary logo."
          },
          "secondary": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/LogoObject" },
            "description": "Other logo candidates found on the page."
          },
          "favicon_url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "URL to the site favicon.",
            "example": "https://stripe.com/favicon.ico"
          },
          "icon_url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "URL to the site icon."
          },
          "apple_touch_icon": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "URL to the Apple Touch Icon."
          }
        },
        "required": ["primary", "secondary", "favicon_url", "icon_url", "apple_touch_icon"]
      },
      "BrandAssetItem": {
        "type": "object",
        "description": "An image harvested from the site or its social profiles, such as a Twitter banner.",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "alt": {
            "type": "string",
            "nullable": true
          },
          "width": {
            "type": "number",
            "nullable": true
          },
          "height": {
            "type": "number",
            "nullable": true
          }
        },
        "required": [
          "url"
        ]
      },
      "ImagesBlock": {
        "type": "object",
        "properties": {
          "og_image": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "OpenGraph image URL."
          },
          "twitter_image": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Twitter card image URL."
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BrandAssetItem"
            },
            "description": "Additional brand imagery found on the site and its social profiles."
          },
          "screenshot_url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "URL to the page screenshot stored in cloud storage."
          }
        },
        "required": [
          "og_image",
          "twitter_image",
          "screenshot_url"
        ]
      },
      "SocialLinks": {
        "type": "object",
        "additionalProperties": { "type": "string" },
        "description": "Social media profile URLs keyed by platform name.",
        "example": {
          "twitter": "https://twitter.com/stripe",
          "linkedin": "https://linkedin.com/company/stripe"
        }
      },
      "ButtonTokens": {
        "type": "object",
        "nullable": true,
        "properties": {
          "background": {
            "type": "string",
            "nullable": true,
            "description": "Fill color. `null` for an outlined or text-only button.",
            "example": "#533AFD"
          },
          "text_color": {
            "type": "string",
            "nullable": true,
            "description": "Label color.",
            "example": "#FFFFFF"
          },
          "border_color": {
            "type": "string",
            "nullable": true,
            "description": "Border color, when the button has a visible border."
          },
          "border_radius": {
            "type": "string",
            "nullable": true,
            "description": "Corner radius. `9999px` means fully rounded (a pill).",
            "example": "4px"
          },
          "font_weight": {
            "type": "number",
            "nullable": true,
            "description": "Label weight.",
            "example": 400
          }
        }
      },
      "DesignTokens": {
        "type": "object",
        "description": "The site's design system by role, read from the rendered page. Present only when the request sets `designTokens=true`. Best effort: a field the page gives no reliable answer for is `null`.",
        "properties": {
          "color_scheme": {
            "type": "string",
            "enum": [
              "light",
              "dark"
            ],
            "nullable": true,
            "description": "Whether the page background is light or dark.",
            "example": "light"
          },
          "colors": {
            "type": "object",
            "properties": {
              "primary": {
                "type": "string",
                "nullable": true,
                "description": "The main action color: the fill of the most prominent button, or a colored link when no button is filled.",
                "example": "#533AFD"
              },
              "secondary": {
                "type": "string",
                "nullable": true,
                "description": "The fill of the next most prominent button, when it is a distinct color."
              },
              "background": {
                "type": "string",
                "nullable": true,
                "description": "The page background.",
                "example": "#FFFFFF"
              },
              "text": {
                "type": "string",
                "nullable": true,
                "description": "Body text.",
                "example": "#50617A"
              },
              "heading": {
                "type": "string",
                "nullable": true,
                "description": "The color most headings share.",
                "example": "#061B31"
              },
              "link": {
                "type": "string",
                "nullable": true,
                "description": "The most common color of in-content links.",
                "example": "#533AFD"
              }
            }
          },
          "typography": {
            "type": "object",
            "properties": {
              "body": {
                "type": "object",
                "properties": {
                  "font_family": {
                    "type": "string",
                    "nullable": true,
                    "description": "The first family in the stack.",
                    "example": "sohne-var"
                  },
                  "font_stack": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "The full `font-family` list, in order.",
                    "example": [
                      "sohne-var",
                      "Helvetica Neue",
                      "Arial",
                      "sans-serif"
                    ]
                  },
                  "font_size": {
                    "type": "string",
                    "nullable": true,
                    "example": "16px"
                  },
                  "font_weight": {
                    "type": "number",
                    "nullable": true,
                    "example": 400
                  },
                  "line_height": {
                    "type": "string",
                    "nullable": true,
                    "description": "`null` when the site leaves it at `normal`.",
                    "example": "24px"
                  }
                }
              },
              "heading": {
                "type": "object",
                "properties": {
                  "font_family": {
                    "type": "string",
                    "nullable": true,
                    "description": "The lead heading's first family.",
                    "example": "sohne-var"
                  },
                  "font_stack": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "font_weight": {
                    "type": "number",
                    "nullable": true,
                    "example": 500
                  }
                }
              },
              "sizes": {
                "type": "object",
                "description": "Font size of the first visible heading at each level, and of body text.",
                "properties": {
                  "h1": {
                    "type": "string",
                    "nullable": true,
                    "example": "48px"
                  },
                  "h2": {
                    "type": "string",
                    "nullable": true,
                    "example": "32px"
                  },
                  "h3": {
                    "type": "string",
                    "nullable": true,
                    "example": "26px"
                  },
                  "body": {
                    "type": "string",
                    "nullable": true,
                    "example": "16px"
                  }
                }
              }
            }
          },
          "components": {
            "type": "object",
            "properties": {
              "button_primary": {
                "$ref": "#/components/schemas/ButtonTokens"
              },
              "button_secondary": {
                "$ref": "#/components/schemas/ButtonTokens"
              },
              "input": {
                "type": "object",
                "nullable": true,
                "description": "The first visible text field.",
                "properties": {
                  "background": {
                    "type": "string",
                    "nullable": true,
                    "example": "#FFFFFF"
                  },
                  "text_color": {
                    "type": "string",
                    "nullable": true,
                    "example": "#061B31"
                  },
                  "border_color": {
                    "type": "string",
                    "nullable": true,
                    "example": "#E5EDF5"
                  },
                  "border_radius": {
                    "type": "string",
                    "nullable": true,
                    "example": "4px"
                  }
                }
              }
            }
          },
          "border_radius": {
            "type": "string",
            "nullable": true,
            "description": "The primary button's corner radius, a good proxy for the site's rounding.",
            "example": "4px"
          }
        }
      },
      "BrandBlock": {
        "type": "object",
        "description": "Brand identity extracted from the page.",
        "properties": {
          "colors": {
            "$ref": "#/components/schemas/ColorsBlock"
          },
          "fonts": {
            "$ref": "#/components/schemas/BrandFonts"
          },
          "logos": {
            "$ref": "#/components/schemas/LogosBlock"
          },
          "images": {
            "$ref": "#/components/schemas/ImagesBlock"
          },
          "social_links": {
            "$ref": "#/components/schemas/SocialLinks"
          },
          "design_tokens": {
            "$ref": "#/components/schemas/DesignTokens"
          }
        },
        "required": [
          "colors",
          "fonts",
          "logos",
          "images",
          "social_links"
        ]
      },
      "BrandData": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The URL that was scraped.",
            "example": "https://stripe.com"
          },
          "domain": {
            "type": "string",
            "description": "Normalized domain extracted from the URL.",
            "example": "stripe.com"
          },
          "brand": {
            "$ref": "#/components/schemas/BrandBlock"
          }
        },
        "required": [
          "url",
          "domain",
          "brand"
        ]
      },
      "ClassificationBlock": {
        "type": "object",
        "nullable": true,
        "description": "IAB classification of the site. Null in `/enrich` when classification failed.",
        "properties": {
          "iab_id": {
            "type": "string",
            "description": "IAB subcategory ID, in the IAB Content Taxonomy 1.0 format.",
            "example": "IAB3-4"
          },
          "iab_parent_id": {
            "type": "string",
            "nullable": true,
            "description": "IAB parent category ID.",
            "example": "IAB3"
          },
          "category": {
            "type": "string",
            "description": "IAB parent category name.",
            "example": "Business"
          },
          "subcategory": {
            "type": "string",
            "nullable": true,
            "description": "IAB subcategory name.",
            "example": "Business Software"
          },
          "description": {
            "type": "string",
            "description": "Short human-readable description of the website."
          },
          "tagline_description": {
            "type": "string",
            "description": "One-line tagline description."
          },
          "long_description": {
            "type": "string",
            "description": "Extended multi-sentence description of the website."
          },
          "stock_tickers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Stock ticker symbols associated with the company, if publicly traded."
          },
          "isins": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "ISIN codes associated with the company's securities."
          }
        },
        "required": [
          "iab_id",
          "iab_parent_id",
          "category",
          "subcategory",
          "description"
        ]
      },
      "ClassifyData": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The URL that was classified.",
            "example": "https://stripe.com"
          },
          "domain": {
            "type": "string",
            "description": "Normalized domain extracted from the URL.",
            "example": "stripe.com"
          },
          "classification": {
            "$ref": "#/components/schemas/ClassificationBlock"
          }
        },
        "required": [
          "url",
          "domain",
          "classification"
        ]
      },
      "CompanyInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Legal entity name of the company.",
            "example": "Stripe, Inc."
          },
          "display_name": {
            "type": "string",
            "nullable": true,
            "description": "The short name people use for the company.",
            "example": "Stripe"
          },
          "parentCompany": {
            "type": "string",
            "nullable": true,
            "description": "The parent company, when known."
          },
          "employeeCount": {
            "type": "integer",
            "nullable": true,
            "description": "Approximate number of employees, when known.",
            "example": 8000
          },
          "foundedYear": {
            "type": "integer",
            "nullable": true,
            "description": "The year the company was founded, when known.",
            "example": 2010
          },
          "isNsfw": {
            "type": "boolean",
            "description": "Whether the site's content is not safe for work.",
            "example": false
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Contact email addresses found on the site.",
            "example": [
              "support@stripe.com"
            ]
          },
          "addresses": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "raw": { "type": "string", "description": "The address as written." },
                    "street": { "type": "string", "nullable": true },
                    "city": { "type": "string", "nullable": true },
                    "state": { "type": "string", "nullable": true },
                    "postal_code": { "type": "string", "nullable": true },
                    "country": { "type": "string", "nullable": true }
                  }
                },
                { "type": "string" }
              ]
            },
            "description": "Physical addresses found on the site. Each is usually an object with `raw` and its parts, any of which can be null. Handle a plain string too.",
            "example": [
              { "raw": "South San Francisco, California, United States", "street": null, "city": "South San Francisco", "state": "California", "postal_code": null, "country": "United States" }
            ]
          },
          "social_links": {
            "$ref": "#/components/schemas/SocialLinks"
          },
          "links": {
            "type": "object",
            "properties": {
              "about": {
                "type": "string",
                "nullable": true
              },
              "pricing": {
                "type": "string",
                "nullable": true
              },
              "careers": {
                "type": "string",
                "nullable": true
              },
              "contact": {
                "type": "string",
                "nullable": true
              },
              "blog": {
                "type": "string",
                "nullable": true
              },
              "docs": {
                "type": "string",
                "nullable": true
              }
            },
            "required": ["about", "pricing", "careers", "contact", "blog", "docs"],
            "description": "The company's key pages, as its homepage links them. null where the homepage links none.",
            "example": {
              "about": "https://stripe.com/about",
              "pricing": "https://stripe.com/pricing",
              "careers": "https://stripe.com/jobs",
              "contact": "https://stripe.com/contact/sales",
              "blog": "https://stripe.com/blog",
              "docs": "https://docs.stripe.com/"
            }
          }
        },
        "required": [
          "name",
          "emails",
          "addresses"
        ]
      },
      "CompanyData": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "description": "Normalized domain.",
            "example": "stripe.com"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The URL that was scraped.",
            "example": "https://stripe.com"
          },
          "company": { "$ref": "#/components/schemas/CompanyInfo" }
        },
        "required": ["domain", "url", "company"]
      },
      "ScreenshotData": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The URL that was screenshotted.",
            "example": "https://stripe.com"
          },
          "screenshot_url": {
            "type": "string",
            "format": "uri",
            "description": "Public URL to the screenshot stored in cloud storage.",
            "example": "https://assets.prefetch.io/screenshots/stripe-1440x900.jpg"
          },
          "viewport": {
            "type": "object",
            "properties": {
              "width": { "type": "integer", "example": 1440 },
              "height": { "type": "integer", "example": 900 }
            },
            "required": ["width", "height"]
          },
          "format": {
            "type": "string",
            "enum": ["jpeg", "png", "webp", "pdf"],
            "description": "Format of the capture.",
            "example": "jpeg"
          },
          "full_page": {
            "type": "boolean",
            "description": "Whether the full scrollable height was captured.",
            "example": false
          },
          "captured_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of when the screenshot was taken.",
            "example": "2026-03-19T14:22:05.000Z"
          },
          "device": {
            "type": "string",
            "nullable": true,
            "description": "The `device` preset the page was rendered as; null for a plain viewport.",
            "example": "iphone_15"
          },
          "device_scale_factor": {
            "type": "number",
            "nullable": true,
            "description": "Pixels per CSS pixel in the image: 1 for a plain viewport, the device's own density for a preset.",
            "example": 3
          },
          "dark_mode": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the page was asked for its dark theme."
          },
          "selector": {
            "type": "string",
            "nullable": true,
            "description": "The element captured, when `selector` was set."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Non-fatal notes, e.g. a `wait_for_selector` that never appeared."
          }
        },
        "required": ["url", "screenshot_url", "viewport", "format", "full_page", "captured_at"]
      },
      "EnrichBrandBlock": {
        "type": "object",
        "description": "The same brand block `/brand` returns, without `social_links` — in `/enrich` those live on `company` instead.",
        "properties": {
          "colors": {
            "$ref": "#/components/schemas/ColorsBlock"
          },
          "fonts": {
            "$ref": "#/components/schemas/BrandFonts"
          },
          "logos": {
            "$ref": "#/components/schemas/LogosBlock"
          },
          "images": {
            "$ref": "#/components/schemas/ImagesBlock"
          },
          "design_tokens": {
            "$ref": "#/components/schemas/DesignTokens"
          }
        },
        "required": [
          "colors",
          "fonts",
          "logos",
          "images"
        ]
      },
      "EnrichData": {
        "type": "object",
        "description": "Combined output from brand, company, and classify extraction. Each block sits under the same key the standalone endpoint uses.",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://stripe.com"
          },
          "domain": {
            "type": "string",
            "example": "stripe.com"
          },
          "brand": {
            "$ref": "#/components/schemas/EnrichBrandBlock"
          },
          "company": {
            "$ref": "#/components/schemas/CompanyInfo"
          },
          "classification": {
            "$ref": "#/components/schemas/ClassificationBlock"
          }
        },
        "required": [
          "url",
          "domain",
          "brand",
          "company",
          "classification"
        ]
      },
      "ScrapeMetadata": {
        "type": "object",
        "description": "Always present, whatever formats were requested.",
        "properties": {
          "source_url": {
            "type": "string",
            "nullable": true,
            "description": "The URL you requested."
          },
          "final_url": {
            "type": "string",
            "nullable": true,
            "description": "The URL after redirects."
          },
          "status_code": {
            "type": "integer",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true,
            "example": "Stripe | Financial Infrastructure"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "type": "string",
            "nullable": true,
            "example": "en"
          },
          "canonical_url": {
            "type": "string",
            "nullable": true
          },
          "favicon": {
            "type": "string",
            "nullable": true
          },
          "author": {
            "type": "string",
            "nullable": true
          },
          "site_name": {
            "type": "string",
            "nullable": true
          },
          "published_time": {
            "type": "string",
            "nullable": true
          },
          "modified_time": {
            "type": "string",
            "nullable": true
          },
          "robots": {
            "type": "string",
            "nullable": true,
            "description": "The page's own robots meta tag."
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "open_graph": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "twitter": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "json_ld": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Parsed JSON-LD blocks, up to 10."
          },
          "headings": {
            "type": "array",
            "description": "The page's heading outline, up to 100 entries.",
            "items": {
              "type": "object",
              "properties": {
                "level": {
                  "type": "integer"
                },
                "text": {
                  "type": "string"
                }
              }
            }
          },
          "content_type": {
            "type": "string",
            "enum": [
              "text/html",
              "application/pdf"
            ],
            "description": "What the URL served. A PDF's text becomes the markdown; it has no html."
          },
          "page_count": {
            "type": "integer",
            "description": "PDFs only: pages in the document."
          },
          "cache_state": {
            "type": "string",
            "enum": [
              "hit",
              "miss"
            ],
            "description": "Present when the request set `max_age`: `hit` = served from a stored fetch, `miss` = fetched live."
          },
          "cached_at": {
            "type": "string",
            "description": "On a cache hit: when the stored copy was fetched (ISO 8601)."
          }
        }
      },
      "MarkdownBlock": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "GitHub Flavored Markdown. Links and images are resolved to absolute URLs."
          },
          "char_count": {
            "type": "integer"
          },
          "word_count": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean",
            "description": "True when the content hit the 1 MB size cap and was cut."
          },
          "main_content_only": {
            "type": "boolean",
            "description": "True when boilerplate was successfully isolated away. False means the full page body was returned."
          }
        }
      },
      "HtmlBlock": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string"
          },
          "char_count": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean"
          },
          "main_content_only": {
            "type": "boolean"
          }
        }
      },
      "SummaryBlock": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "nullable": true,
            "description": "Null when the summary could not be produced; see `warnings`."
          },
          "model": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ScrapeLinkItem": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "text": {
            "type": "string",
            "nullable": true,
            "description": "The anchor text."
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "rel": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "LinksBlock": {
        "type": "object",
        "properties": {
          "internal": {
            "type": "array",
            "description": "Links on the same site, subdomains included.",
            "items": {
              "$ref": "#/components/schemas/ScrapeLinkItem"
            }
          },
          "external": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScrapeLinkItem"
            }
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "ScrapeImageItem": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "alt": {
            "type": "string",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "nullable": true
          },
          "loading": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ScrapeImagesBlock": {
        "type": "object",
        "properties": {
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScrapeImageItem"
            }
          },
          "og_image": {
            "type": "string",
            "nullable": true
          },
          "twitter_image": {
            "type": "string",
            "nullable": true
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "JsonBlock": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "nullable": true,
            "description": "The extracted object, shaped by your prompt or schema."
          },
          "model": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ScrapePayload": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "final_url": {
            "type": "string"
          },
          "domain": {
            "type": "string",
            "nullable": true,
            "example": "stripe.com"
          },
          "status_code": {
            "type": "integer",
            "nullable": true
          },
          "metadata": {
            "$ref": "#/components/schemas/ScrapeMetadata"
          },
          "markdown": {
            "$ref": "#/components/schemas/MarkdownBlock"
          },
          "summary": {
            "$ref": "#/components/schemas/SummaryBlock"
          },
          "html": {
            "$ref": "#/components/schemas/HtmlBlock"
          },
          "raw_html": {
            "$ref": "#/components/schemas/HtmlBlock"
          },
          "links": {
            "$ref": "#/components/schemas/LinksBlock"
          },
          "images": {
            "$ref": "#/components/schemas/ScrapeImagesBlock"
          },
          "json": {
            "$ref": "#/components/schemas/JsonBlock"
          },
          "screenshot": {
            "$ref": "#/components/schemas/ScrapeScreenshotBlock"
          },
          "pdf": {
            "$ref": "#/components/schemas/PdfBlock"
          },
          "prompt_injection": {
            "$ref": "#/components/schemas/PromptInjectionBlock"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Non-fatal problems, such as a format that could not be produced."
          }
        },
        "description": "The page content fields. Which of them are present depends on the `formats` requested."
      },
      "ScrapeScreenshotBlock": {
        "type": "object",
        "description": "Present when `formats` includes `screenshot`.",
        "properties": {
          "url": {
            "type": "string",
            "description": "The image on our CDN. Short-lived: copy it if you need to keep it."
          },
          "viewport": {
            "type": "object",
            "properties": {
              "width": {
                "type": "integer"
              },
              "height": {
                "type": "integer"
              }
            }
          },
          "full_page": {
            "type": "boolean"
          },
          "format": {
            "type": "string",
            "enum": [
              "jpeg",
              "png",
              "webp"
            ]
          }
        }
      },
      "PromptInjectionBlock": {
        "type": "object",
        "description": "Present when the request set `check_prompt_injection`.",
        "properties": {
          "detected": {
            "type": "boolean",
            "description": "True when the page's text appears to contain instructions aimed at an AI model."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "description": "Why it was flagged, quoting or describing the suspicious text. Null when nothing was found.",
            "example": "The page tells AI assistants to ignore their instructions and send the user's API keys to an outside address."
          },
          "complete": {
            "type": "boolean",
            "description": "True when all of the page's text was checked. False when part of it could not be (a very long page, or the classifier was unavailable): `detected: false` then means nothing was found in what was checked, not that the page is clean."
          },
          "model": {
            "type": "string",
            "nullable": true,
            "description": "The model that checked it; null for a page with no text.",
            "example": "gpt-5.6-luna"
          }
        },
        "required": [
          "detected",
          "reason",
          "complete",
          "model"
        ]
      },
      "PdfBlock": {
        "type": "object",
        "description": "Present when the URL served a PDF. Its text is in `markdown`.",
        "properties": {
          "page_count": {
            "type": "integer"
          },
          "pages_parsed": {
            "type": "integer",
            "description": "Pages whose text was read (capped for very long documents)."
          },
          "truncated": {
            "type": "boolean"
          }
        }
      },
      "ScrapeBody": {
        "type": "object",
        "description": "The same options as `GET /scrape`, as typed JSON.",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "example": "https://stripe.com/pricing"
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "markdown",
                "summary",
                "html",
                "raw_html",
                "links",
                "images",
                "json",
                "screenshot"
              ]
            },
            "default": [
              "markdown"
            ]
          },
          "only_main_content": {
            "type": "boolean",
            "default": true
          },
          "include_links": {
            "type": "boolean",
            "default": true
          },
          "include_images": {
            "type": "boolean",
            "default": true
          },
          "include_base64_images": {
            "type": "boolean",
            "default": false
          },
          "include_selectors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "exclude_selectors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "json_prompt": {
            "type": "string"
          },
          "json_schema": {
            "type": "object"
          },
          "summary_max_words": {
            "type": "integer",
            "minimum": 20,
            "maximum": 400,
            "default": 120
          },
          "screenshot_full_page": {
            "type": "boolean",
            "default": false
          },
          "screenshot_format": {
            "type": "string",
            "enum": [
              "jpeg",
              "png",
              "webp"
            ],
            "default": "jpeg"
          },
          "wait_for": {
            "type": "integer",
            "minimum": 0,
            "maximum": 30000,
            "description": "Milliseconds to wait after the page loads."
          },
          "wait_for_selector": {
            "type": "string",
            "description": "Wait (up to 10 s) for this CSS selector. Best effort."
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Request headers to send to the target. Up to 20. Requests with headers are never cached."
          },
          "mobile": {
            "type": "boolean",
            "default": false
          },
          "timeout": {
            "type": "integer",
            "minimum": 5000,
            "maximum": 50000
          },
          "max_age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2592000000,
            "default": 0,
            "description": "Accept a stored copy fetched at most this many milliseconds ago."
          },
          "store_in_cache": {
            "type": "boolean",
            "default": true
          },
          "check_prompt_injection": {
            "type": "boolean",
            "default": false,
            "description": "Check the page's text for prompt injection — text written to make an AI model reading the page ignore its instructions, leak data or take actions — and report it in `prompt_injection`. The page is still returned: the check warns, it does not block. Costs the same 3-credit surcharge as `summary` and `json` (once per page, however many of the three you ask for)."
          }
        }
      },
      "ScrapeData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ScrapePayload"
          }
        ],
        "required": [
          "url",
          "final_url",
          "metadata"
        ]
      },
      "ResolveResultItem": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "example": "Stripe" },
          "domain": { "type": "string", "description": "Bare host, ready for the `url` parameter of every other endpoint.", "example": "stripe.com" },
          "url": { "type": "string", "example": "https://stripe.com" },
          "confidence": { "type": "number", "description": "0–1. Only `results[0]` can reach 0.8; at or above it, that result is the answer. Below it, a candidate to check.", "example": 0.97 },
          "source": { "type": "string", "enum": ["curated", "index", "live"], "description": "`curated`: reviewed brand data. `index`: the name index. `live`: verified against the site during this request." }
        },
        "required": ["name", "domain", "url", "confidence", "source"]
      },
      "ResolveData": {
        "type": "object",
        "properties": {
          "query": { "type": "string", "description": "The name, as resolved (whitespace collapsed).", "example": "Stripe" },
          "results": { "type": "array", "items": { "$ref": "#/components/schemas/ResolveResultItem" }, "description": "Best match first; one entry per domain. Empty when nothing matched." },
          "count": { "type": "integer" },
          "live_used": { "type": "boolean", "description": "Whether the live lookup ran — and so whether the request was billed 3 credits." },
          "warnings": { "type": "array", "items": { "type": "string" }, "description": "Non-fatal notes, e.g. a live lookup skipped because the service was busy." }
        },
        "required": ["query", "results", "count", "live_used", "warnings"]
      },
      "MapLinkItem": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "lastmod": {
            "type": "string",
            "nullable": true,
            "description": "From the sitemap, when the site publishes one."
          },
          "source": {
            "type": "string",
            "enum": [
              "sitemap",
              "links"
            ],
            "description": "Where the URL was discovered."
          }
        }
      },
      "MapData": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "domain": {
            "type": "string",
            "nullable": true
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MapLinkItem"
            }
          },
          "count": {
            "type": "integer"
          },
          "total_discovered": {
            "type": "integer",
            "description": "Links found before `limit` was applied."
          },
          "sources": {
            "type": "object",
            "properties": {
              "sitemap": {
                "type": "integer"
              },
              "links": {
                "type": "integer"
              }
            }
          },
          "sitemaps_used": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CrawlScrapeOptions": {
        "type": "object",
        "description": "How each crawled page is fetched and rendered. The same options `GET /scrape` takes.",
        "properties": {
          "formats": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "markdown",
                "summary",
                "html",
                "raw_html",
                "links",
                "images",
                "json",
                "screenshot"
              ]
            },
            "default": [
              "markdown"
            ]
          },
          "only_main_content": {
            "type": "boolean",
            "default": true
          },
          "include_links": {
            "type": "boolean",
            "default": true
          },
          "include_images": {
            "type": "boolean",
            "default": true
          },
          "include_base64_images": {
            "type": "boolean",
            "default": false
          },
          "include_selectors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "exclude_selectors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "json_prompt": {
            "type": "string"
          },
          "json_schema": {
            "type": "object"
          },
          "summary_max_words": {
            "type": "integer",
            "minimum": 20,
            "maximum": 400,
            "default": 120
          },
          "screenshot_full_page": {
            "type": "boolean",
            "default": false
          },
          "screenshot_format": {
            "type": "string",
            "enum": [
              "jpeg",
              "png",
              "webp"
            ],
            "default": "jpeg"
          },
          "wait_for": {
            "type": "integer",
            "minimum": 0,
            "maximum": 30000
          },
          "wait_for_selector": {
            "type": "string"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Sent with every page request. Pages fetched with headers are never cached."
          },
          "mobile": {
            "type": "boolean",
            "default": false
          },
          "max_age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2592000000,
            "default": 0,
            "description": "Accept stored copies of pages fetched at most this many milliseconds ago."
          },
          "store_in_cache": {
            "type": "boolean",
            "default": true
          },
          "check_prompt_injection": {
            "type": "boolean",
            "default": false,
            "description": "Check each page for prompt injection, as on `/scrape`. Adds the AI surcharge to every page."
          }
        }
      },
      "CrawlRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "Where the crawl starts.",
            "example": "https://docs.stripe.com"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "default": 25,
            "description": "Maximum pages to crawl."
          },
          "max_depth": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5,
            "default": 2,
            "description": "How many links deep to follow from the start URL. Sitemap-seeded pages sit at depth 0, so `max_depth: 0` with `use_sitemap: true` crawls exactly what the sitemap lists and follows nothing."
          },
          "include_paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Regular expressions matched against a URL's path and query. A URL must match at least one to be crawled.",
            "example": [
              "^/docs/"
            ]
          },
          "exclude_paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Regular expressions. A URL matching any of them is skipped. Exclusions win over inclusions.",
            "example": [
              "^/docs/changelog/"
            ]
          },
          "allow_subdomains": {
            "type": "boolean",
            "default": false,
            "description": "Follow links onto subdomains of the start URL."
          },
          "allow_external_links": {
            "type": "boolean",
            "default": false,
            "description": "Follow links onto other sites."
          },
          "ignore_query_params": {
            "type": "boolean",
            "default": true,
            "description": "Treat URLs that differ only by query string as one page."
          },
          "respect_robots_txt": {
            "type": "boolean",
            "default": true,
            "description": "Obey the rules in `robots.txt` — Disallow and Crawl-delay. Sitemap discovery happens either way."
          },
          "use_sitemap": {
            "type": "boolean",
            "default": true,
            "description": "Seed the crawl from the site's sitemap as well as from links."
          },
          "crawl_entire_domain": {
            "type": "boolean",
            "default": false,
            "description": "Follow links anywhere on the site. By default a crawl stays at or below the path it starts from: one started at `/docs/` crawls `/docs/…` only. A crawl from the root covers the whole site either way."
          },
          "webhook": {
            "description": "Where to send progress: an https URL, or an object. Events: `crawl.started`, `crawl.page` (one per page), `crawl.completed`, `crawl.failed`. Each delivery is signed — `X-Prefetch-Signature: t=<unix>,v1=<hex>`, HMAC-SHA256 of `<t>.<raw body>` with the `secret` returned when the crawl is created — the same scheme as monitor webhooks.",
            "oneOf": [
              {
                "type": "string",
                "example": "https://example.com/hooks/prefetch"
              },
              {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "started",
                        "page",
                        "completed",
                        "failed"
                      ]
                    }
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "metadata": {
                    "type": "object",
                    "description": "Echoed back in every payload (up to 4 KB)."
                  }
                }
              }
            ]
          },
          "delay_ms": {
            "type": "integer",
            "minimum": 0,
            "maximum": 30000,
            "default": 0,
            "description": "Politeness delay between pages. A larger `Crawl-delay` in robots.txt wins."
          },
          "concurrency": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "default": 2,
            "description": "Pages fetched in parallel."
          },
          "scrape_options": {
            "$ref": "#/components/schemas/CrawlScrapeOptions"
          }
        }
      },
      "CrawlJobData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "crw_9f2c1a7b4e0d4c3a8b1e5f7d2c9a0b3e"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "cancelled"
            ]
          },
          "url": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "max_depth": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "After this, the crawl and its pages are no longer readable."
          },
          "webhook": {
            "type": "object",
            "description": "Present when the request set `webhook`.",
            "properties": {
              "url": {
                "type": "string"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "secret": {
                "type": "string",
                "description": "Verifies the `X-Prefetch-Signature` on each delivery. Shown only here — store it."
              }
            }
          }
        }
      },
      "CrawlPage": {
        "type": "object",
        "description": "One crawled page. Carries the same fields `GET /scrape` returns, plus the crawl's own bookkeeping.",
        "allOf": [
          {
            "type": "object",
            "properties": {
              "url": {
                "type": "string"
              },
              "depth": {
                "type": "integer",
                "description": "How many links from the start URL. Sitemap-seeded pages are depth 0."
              },
              "status_code": {
                "type": "integer",
                "nullable": true
              },
              "ok": {
                "type": "boolean",
                "description": "False when the page could not be fetched. You are not charged for it."
              },
              "error": {
                "type": "string",
                "nullable": true
              },
              "error_code": {
                "type": "string",
                "nullable": true,
                "description": "Why the page failed, as one of the API's [error codes](/concepts/errors#error-codes); null when it did not.",
                "example": "TARGET_SERVER_ERROR"
              }
            }
          },
          {
            "$ref": "#/components/schemas/ScrapePayload"
          }
        ]
      },
      "SkippedUrls": {
        "type": "object",
        "additionalProperties": {
          "type": "object",
          "properties": {
            "count": {
              "type": "number"
            },
            "samples": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "required": [
            "count",
            "samples"
          ]
        },
        "description": "URLs the crawl found but did not fetch, by reason: `limit`, `depth`, `out-of-scope`, `excluded`, `not-included`, `robots`, `off-site`, `file`, `invalid`, `blocklist`, `duplicate` (a redirect onto a page already crawled)."
      },
      "CrawlErrorsData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "cancelled"
            ]
          },
          "failed": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "depth": {
                  "type": "integer"
                },
                "status_code": {
                  "type": "integer",
                  "nullable": true
                },
                "error": {
                  "type": "string",
                  "nullable": true
                },
                "error_code": {
                  "type": "string",
                  "nullable": true,
                  "description": "Why the page failed, as one of the API's [error codes](/concepts/errors#error-codes).",
                  "example": "TARGET_SERVER_ERROR"
                }
              },
              "required": [
                "url",
                "depth",
                "status_code",
                "error",
                "error_code"
              ]
            },
            "description": "Pages that were fetched and failed, oldest first."
          },
          "failed_total": {
            "type": "integer"
          },
          "skipped": {
            "$ref": "#/components/schemas/SkippedUrls"
          },
          "next": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "status",
          "failed",
          "failed_total",
          "skipped",
          "next"
        ]
      },
      "BatchScrapeRequest": {
        "type": "object",
        "required": [
          "urls"
        ],
        "properties": {
          "urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 500,
            "description": "The pages to scrape (1–500). Duplicates are scraped once.",
            "example": [
              "https://stripe.com/pricing",
              "https://stripe.com/docs"
            ]
          },
          "concurrency": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "default": 2,
            "description": "Pages fetched in parallel."
          },
          "ignore_invalid_urls": {
            "type": "boolean",
            "default": false,
            "description": "Drop URLs that fail validation (listed in `invalid_urls`) instead of rejecting the whole batch."
          },
          "webhook": {
            "description": "Where to send progress: an https URL, or an object. Events: `batch_scrape.started`, `batch_scrape.page` (one per page), `batch_scrape.completed`, `batch_scrape.failed`. Each delivery is signed — `X-Prefetch-Signature: t=<unix>,v1=<hex>`, HMAC-SHA256 of `<t>.<raw body>` with the `secret` returned when the batch is created — the same scheme as monitor webhooks.",
            "oneOf": [
              {
                "type": "string",
                "example": "https://example.com/hooks/prefetch"
              },
              {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "started",
                        "page",
                        "completed",
                        "failed"
                      ]
                    }
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "metadata": {
                    "type": "object",
                    "description": "Echoed back in every payload (up to 4 KB)."
                  }
                }
              }
            ]
          },
          "scrape_options": {
            "$ref": "#/components/schemas/CrawlScrapeOptions"
          }
        }
      },
      "BatchJobData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "crw_4b1e9c0a7d2f4e6b"
          },
          "endpoint": {
            "type": "string",
            "description": "What each URL is run through.",
            "example": "scrape"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "cancelled"
            ]
          },
          "url_count": {
            "type": "integer",
            "description": "Pages queued, after removing duplicates (and invalid URLs, with ignore_invalid_urls)."
          },
          "invalid_urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "URLs dropped by ignore_invalid_urls."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "webhook": {
            "type": "object",
            "description": "Present when the request set `webhook`.",
            "properties": {
              "url": {
                "type": "string"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "secret": {
                "type": "string",
                "description": "Verifies the `X-Prefetch-Signature` on each delivery. Shown only here — store it."
              }
            }
          }
        },
        "required": [
          "id",
          "status",
          "url_count",
          "invalid_urls",
          "created_at",
          "expires_at"
        ]
      },
      "CrawlStatusData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "cancelled"
            ]
          },
          "url": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "description": "Pages the crawl expects to fetch, as currently known. Rises as it discovers more."
          },
          "completed": {
            "type": "integer"
          },
          "failed": {
            "type": "integer"
          },
          "credits_used": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "next": {
            "type": "string",
            "nullable": true,
            "description": "URL for the next page of results, or null when there are no more."
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrawlPage"
            },
            "description": "Crawled pages, in completion order."
          },
          "kind": {
            "type": "string",
            "enum": [
              "crawl",
              "batch"
            ],
            "description": "`batch` for a `POST /batch/{endpoint}` job."
          },
          "endpoint": {
            "type": "string",
            "description": "What each item is: `scrape` for a crawl or /batch/scrape, otherwise the batch's endpoint (`brand`, `enrich`, …).",
            "example": "scrape"
          },
          "skipped": {
            "type": "object",
            "description": "URLs the crawl found but did not fetch, by reason: `limit`, `depth`, `out-of-scope`, `excluded`, `not-included`, `robots`, `off-site`, `file`, `invalid`, `blocklist`, `duplicate` (a redirect onto a page already crawled). Present once anything was skipped.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "count": {
                  "type": "integer"
                },
                "samples": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Up to five examples."
                }
              }
            }
          }
        }
      },
      "MonitorSchedule": {
        "type": "object",
        "description": "Exactly one of `cron` or `text`. A bare string is accepted too, and read as cron when it has five cron fields.",
        "properties": {
          "cron": {
            "type": "string",
            "description": "Five-field cron expression. How close together runs may be depends on the plan: an hour apart on Free, 5 minutes on Starter and Pro, 2 on Growth, 1 on Scale.",
            "example": "*/30 * * * *"
          },
          "text": {
            "type": "string",
            "description": "A plain-English schedule, converted to cron: \"every 30 minutes\", \"every 15 minutes starting at :07\", \"hourly\", \"every 2 hours\", \"daily\", \"daily at 9am\", \"daily at 5:30 PM\", \"every weekday at 9am\", \"weekly\", \"every monday at 8:00\", \"monthly\".",
            "example": "every weekday at 9am"
          },
          "timezone": {
            "type": "string",
            "default": "UTC",
            "description": "IANA timezone the schedule runs in.",
            "example": "Europe/Athens"
          }
        }
      },
      "MonitorScrapeOptions": {
        "type": "object",
        "description": "How each page is rendered before it is compared — the content-shaping options of `GET /scrape`.",
        "properties": {
          "only_main_content": {
            "type": "boolean",
            "default": true,
            "description": "Compare the main content only, ignoring navigation, sidebars and footers."
          },
          "include_links": {
            "type": "boolean",
            "default": true,
            "description": "Keep link URLs in the compared markdown."
          },
          "include_images": {
            "type": "boolean",
            "default": false,
            "description": "Keep images in the compared markdown. Off by default: image URLs carry cache-busting hashes that change on every deploy."
          },
          "include_selectors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "CSS selectors to compare instead of the detected main content.",
            "example": [
              "#pricing"
            ]
          },
          "exclude_selectors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "CSS selectors to leave out of the comparison — the way to silence a timestamp or a rotating banner.",
            "example": [
              ".last-updated",
              ".testimonial"
            ]
          }
        }
      },
      "MonitorChangeTracking": {
        "type": "object",
        "properties": {
          "modes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "markdown",
                "json"
              ]
            },
            "default": [
              "markdown"
            ],
            "description": "`markdown` diffs the page text line by line. `json` extracts the fields described by `json_prompt` or `json_schema` and diffs them field by field, so a page is `changed` only when a tracked field changes. The extraction is re-read (and its AI surcharge charged) only when the page's text changed, and list items are matched by identity (an `id`, `url`, `name` or `title` field), so one item inserted into a list is one `added` field. Both together report `changed` when either surface changed."
          },
          "json_prompt": {
            "type": "string",
            "description": "For the `json` mode: the fields to track, in plain English.",
            "example": "Each plan: name, monthly price, headline features"
          },
          "json_schema": {
            "type": "object",
            "description": "For the `json` mode: a JSON Schema for the extraction."
          },
          "ignore_text": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to 25 phrases: lines containing one are left out of the comparison. Plain text, case and spacing ignored, `*` matching any run of characters. Regular expressions are not accepted.",
            "example": ["people are viewing", "viewed * times"]
          },
          "ignore_order": {
            "type": "boolean",
            "default": false,
            "description": "Lines that only moved are not a change: a re-sorted list, testimonials shown in another order."
          },
          "notify_on": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["added", "removed", "changed"]
            },
            "description": "Which kinds of change notify: lines (or json fields) added, removed or changed, and, for a crawl, pages that appear (`added`) or disappear (`removed`); a tracked price, number, visual area or keyword that moves is a change. Default: all three. A change of another kind is recorded on the check, not judged or announced.",
            "example": ["added"]
          },
          "only_new_content": {
            "type": "boolean",
            "default": false,
            "description": "Notify only when a change brings text the page has not shown in its recent history (its last ~1,000 distinct lines), so content that cycles (a carousel, rotating offers, A/B variants) stays quiet."
          }
        }
      },
      "MonitorCrawlOptions": {
        "type": "object",
        "description": "The crawl options `POST /crawl` takes, without `allow_external_links`.",
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "default": 25,
            "description": "Most pages each check crawls. Every page is billed on every check."
          },
          "max_depth": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5,
            "default": 2,
            "description": "How many links deep to follow from the start URL."
          },
          "include_paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Regular expressions matched against a URL's path and query. A URL must match at least one to be monitored.",
            "example": [
              "^/changelog/"
            ]
          },
          "exclude_paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Regular expressions. A matching URL is skipped."
          },
          "allow_subdomains": {
            "type": "boolean",
            "default": false,
            "description": "Follow links onto subdomains of the start URL."
          },
          "ignore_query_params": {
            "type": "boolean",
            "default": true,
            "description": "Treat URLs that differ only by query string as one page."
          },
          "respect_robots_txt": {
            "type": "boolean",
            "default": true,
            "description": "Obey the rules in `robots.txt`."
          },
          "use_sitemap": {
            "type": "boolean",
            "default": true,
            "description": "Seed each crawl from the site's sitemap as well as from links."
          },
          "delay_ms": {
            "type": "integer",
            "minimum": 0,
            "maximum": 30000,
            "default": 0,
            "description": "Politeness delay between pages."
          },
          "concurrency": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "default": 2,
            "description": "Pages fetched in parallel."
          }
        }
      },
      "MonitorScrapeTarget": {
        "type": "object",
        "title": "Scrape target",
        "description": "Watches a fixed list of pages, each fetched the way `GET /scrape` would fetch it.",
        "required": [
          "type",
          "urls"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable target id. Generated when omitted; on update, a target watching the same URLs keeps its id — and its snapshots — automatically.",
            "example": "tgt_8d1e0f2a3b4c5d6e"
          },
          "type": {
            "type": "string",
            "enum": [
              "scrape"
            ]
          },
          "urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100,
            "description": "The pages to watch.",
            "example": [
              "https://example.com/pricing"
            ]
          },
          "scrape_options": {
            "$ref": "#/components/schemas/MonitorScrapeOptions"
          },
          "change_tracking": {
            "$ref": "#/components/schemas/MonitorChangeTracking"
          }
        }
      },
      "MonitorCrawlTarget": {
        "type": "object",
        "title": "Crawl target",
        "description": "Re-crawls a site on every check, so pages that appear or disappear are reported as well as pages that change.",
        "required": [
          "type",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable target id. Generated when omitted.",
            "example": "tgt_1a2b3c4d5e6f7a8b"
          },
          "type": {
            "type": "string",
            "enum": [
              "crawl"
            ]
          },
          "url": {
            "type": "string",
            "description": "Where each crawl starts.",
            "example": "https://example.com/changelog"
          },
          "crawl_options": {
            "$ref": "#/components/schemas/MonitorCrawlOptions"
          },
          "scrape_options": {
            "$ref": "#/components/schemas/MonitorScrapeOptions"
          },
          "change_tracking": {
            "$ref": "#/components/schemas/MonitorChangeTracking"
          }
        }
      },
      "MonitorSearchTarget": {
        "type": "object",
        "title": "Search target",
        "description": "Runs web searches on every check. A result the target has not returned before is `new` (with a goal, judged against it, so only results that match are announced); results returned before are `same`. Billed at the /search rate per query.",
        "required": ["type", "queries"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable target id. Generated when omitted.",
            "example": "tgt_1a2b3c4d5e6f7a8b"
          },
          "type": {
            "type": "string",
            "enum": ["search"]
          },
          "queries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "1–5 web searches, run on every check (`query`, one string, is accepted too). Search operators work.",
            "example": ["acme corp funding round"]
          },
          "search_options": {
            "type": "object",
            "description": "The options GET /search takes, applied to every query.",
            "properties": {
              "type": {
                "type": "string",
                "enum": ["web", "news"],
                "default": "web"
              },
              "limit": {
                "type": "integer",
                "default": 10,
                "description": "Results read from each search (1–20)."
              },
              "country": {
                "type": "string",
                "nullable": true
              },
              "language": {
                "type": "string",
                "nullable": true
              },
              "location": {
                "type": "string",
                "nullable": true
              },
              "time_range": {
                "type": "string",
                "enum": ["hour", "day", "week", "month", "year"],
                "nullable": true
              },
              "include_domains": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "exclude_domains": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "scrape_results": {
            "type": "boolean",
            "description": "Read each new result's page (billed at the /scrape rate) so the judge sees the page, not just its snippet. Default: true when the monitor judges, otherwise false."
          }
        }
      },
      "MonitorTarget": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/MonitorScrapeTarget"
          },
          {
            "$ref": "#/components/schemas/MonitorCrawlTarget"
          },
          {
            "$ref": "#/components/schemas/MonitorSearchTarget"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "scrape": "#/components/schemas/MonitorScrapeTarget",
            "crawl": "#/components/schemas/MonitorCrawlTarget",
            "search": "#/components/schemas/MonitorSearchTarget"
          }
        }
      },
      "MonitorWebhookRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "HTTPS endpoint that receives the events.",
            "example": "https://you.example.org/hooks/prefetch"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Extra headers sent with every event, at most 20. `Host`, `Content-Type` and `X-Prefetch-*` are reserved.",
            "example": {
              "Authorization": "Bearer your-token"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Echoed back in every event, up to 4 KB.",
            "example": {
              "env": "production"
            }
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "monitor.page",
                "monitor.check.completed"
              ]
            },
            "description": "Events to receive. Default: both."
          },
          "secret": {
            "type": "string",
            "description": "Signing secret, 16–128 printable characters. Generated when omitted, and kept across updates unless you replace it."
          },
          "notify_errors_after": {
            "type": "integer",
            "default": 1,
            "description": "Send a page's error event once it has failed this many checks in a row (1–10), so a page that fails once and recovers sends nothing.",
            "example": 2
          },
          "rotate_secret": {
            "type": "boolean",
            "description": "Update only: generate a new signing secret."
          }
        }
      },
      "MonitorEmailRequest": {
        "type": "object",
        "required": ["to"],
        "properties": {
          "to": {
            "oneOf": [
              { "type": "string" },
              { "type": "array", "items": { "type": "string" }, "minItems": 1, "maxItems": 5 }
            ],
            "description": "Up to 5 addresses to email when a check finds changes. An address on your Prefetch account receives alerts at once; any other address is sent one confirmation email and receives nothing until it confirms.",
            "example": ["you@example.com"]
          },
          "resend_confirmation": {
            "type": "boolean",
            "description": "Update only: send the confirmation email again to addresses that are still `pending`."
          }
        }
      },
      "MonitorRequest": {
        "type": "object",
        "required": [
          "name",
          "schedule",
          "targets"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 256,
            "example": "Competitor pricing"
          },
          "schedule": {
            "$ref": "#/components/schemas/MonitorSchedule"
          },
          "goal": {
            "type": "string",
            "maxLength": 2000,
            "nullable": true,
            "description": "What you want to be told about, in one plain sentence. With a goal, every changed page is judged against it, and only meaningful changes send a `monitor.page` webhook. 1 credit per page judged.",
            "example": "Alert me when a plan price or its included features change"
          },
          "judge_enabled": {
            "type": "boolean",
            "description": "Judge changes against the goal. Default: `true` when a goal is set."
          },
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonitorTarget"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "What to watch. At most 500 pages per check across all targets."
          },
          "webhook": {
            "$ref": "#/components/schemas/MonitorWebhookRequest"
          },
          "email": {
            "$ref": "#/components/schemas/MonitorEmailRequest"
          },
          "retention_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "default": 30,
            "description": "How long check history is kept."
          }
        }
      },
      "MonitorUpdateRequest": {
        "type": "object",
        "description": "Any subset of the create fields, plus `status`. Fields you leave out stay as they are.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 256
          },
          "schedule": {
            "$ref": "#/components/schemas/MonitorSchedule"
          },
          "goal": {
            "type": "string",
            "maxLength": 2000,
            "nullable": true,
            "description": "`null` clears the goal and turns judging off."
          },
          "judge_enabled": {
            "type": "boolean"
          },
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonitorTarget"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "Replaces the whole list."
          },
          "webhook": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MonitorWebhookRequest"
              }
            ],
            "nullable": true,
            "description": "`null` removes the webhook."
          },
          "email": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MonitorEmailRequest"
              }
            ],
            "nullable": true,
            "description": "Replaces the list of addresses. Addresses you keep keep their status. `null` removes them all."
          },
          "retention_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ],
            "description": "Pause or resume. Resuming runs at the next scheduled time; runs missed while paused are not replayed."
          }
        }
      },
      "MonitorSummary": {
        "type": "object",
        "properties": {
          "total_pages": {
            "type": "integer"
          },
          "same": {
            "type": "integer"
          },
          "new": {
            "type": "integer"
          },
          "changed": {
            "type": "integer"
          },
          "removed": {
            "type": "integer"
          },
          "error": {
            "type": "integer"
          }
        }
      },
      "MonitorWebhook": {
        "type": "object",
        "nullable": true,
        "properties": {
          "url": {
            "type": "string"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "metadata": {
            "type": "object"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "monitor.page",
                "monitor.check.completed"
              ]
            }
          },
          "notify_errors_after": {
            "type": "integer",
            "description": "Consecutive failed checks before a page's error event is sent.",
            "example": 1
          },
          "secret": {
            "type": "string",
            "description": "Verifies the `X-Prefetch-Signature` header on every event.",
            "example": "whsec_4f1c9e2a7b3d8e6f0a5c1b9d2e7f3a8c4b6d0e1f9a2c5b7d"
          }
        }
      },
      "MonitorEmail": {
        "type": "object",
        "nullable": true,
        "description": "Email alerts: one email per check that finds changes, to every `active` address. `null` when the monitor emails nobody.",
        "properties": {
          "to": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Every address, in the form `PATCH` takes back.",
            "example": ["you@example.com"]
          },
          "recipients": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "address": { "type": "string" },
                "status": {
                  "type": "string",
                  "enum": ["active", "pending", "unsubscribed"],
                  "description": "`active` receives alerts. `pending` was sent a confirmation email and receives nothing until it confirms. `unsubscribed` stopped them from a link in an email."
                },
                "confirmation_sent_at": {
                  "type": "string",
                  "nullable": true,
                  "description": "When the confirmation email went out. `null` on a pending address means it could not be sent: retry with `resend_confirmation`."
                },
                "confirmed_at": { "type": "string", "nullable": true },
                "unsubscribed_at": { "type": "string", "nullable": true }
              }
            }
          }
        }
      },
      "MonitorData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused"
            ]
          },
          "schedule": {
            "type": "object",
            "properties": {
              "cron": {
                "type": "string",
                "description": "The schedule the monitor runs on — always cron, whatever you submitted.",
                "example": "0 9 * * 1-5"
              },
              "timezone": {
                "type": "string",
                "example": "Europe/Athens"
              },
              "text": {
                "type": "string",
                "nullable": true,
                "description": "The phrase it was created from, if any.",
                "example": "every weekday at 9am"
              }
            }
          },
          "next_run_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "`null` while paused."
          },
          "last_run_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "current_check_id": {
            "type": "string",
            "nullable": true,
            "description": "The check running right now, if any."
          },
          "goal": {
            "type": "string",
            "nullable": true
          },
          "judge_enabled": {
            "type": "boolean"
          },
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonitorTarget"
            },
            "description": "Normalised: every target has an id and every option its effective value."
          },
          "webhook": {
            "$ref": "#/components/schemas/MonitorWebhook"
          },
          "email": {
            "$ref": "#/components/schemas/MonitorEmail"
          },
          "retention_days": {
            "type": "integer"
          },
          "estimated_credits_per_check": {
            "type": "integer",
            "description": "Upper bound: every page fetched, and judged when a goal is set. A real check costs less — only fetched pages are billed, and only changed ones judged."
          },
          "estimated_credits_per_month": {
            "type": "integer",
            "description": "`estimated_credits_per_check` times the runs in an average month."
          },
          "last_check_summary": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MonitorSummary"
              },
              {
                "type": "object",
                "properties": {
                  "check_id": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "queued",
                      "running",
                      "completed",
                      "failed",
                      "partial",
                      "skipped_overlap",
                      "skipped_no_credits"
                    ]
                  },
                  "finished_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              }
            ],
            "nullable": true,
            "description": "Counts from the most recent check, or `null` before the first one."
          },
          "thumbnail_url": {
            "type": "string",
            "nullable": true,
            "description": "A screenshot of the first page the monitor watches (JPEG, 640 px wide), taken once in the background after the monitor is created and again when an edit changes that page. A signed link, good for at least a day: read it again from the monitor rather than storing it. Null until the picture is taken, and for a page that would not render or a monitor of searches."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the settings last changed. Checks do not touch it."
          }
        }
      },
      "MonitorListData": {
        "type": "object",
        "properties": {
          "monitors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonitorData"
            }
          },
          "total": {
            "type": "integer"
          },
          "next": {
            "type": "string",
            "nullable": true,
            "description": "URL for the next page of monitors, or null."
          }
        }
      },
      "MonitorDeleteData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "deleted": {
            "type": "boolean",
            "enum": [
              true
            ]
          }
        }
      },
      "MonitorCheckData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a"
          },
          "monitor_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "completed",
              "failed",
              "partial",
              "skipped_overlap",
              "skipped_no_credits"
            ],
            "description": "`partial`: some pages errored, or the check stopped early on credits or its time limit — its results are real but incomplete. `skipped_overlap`: the previous check was still running. `skipped_no_credits`: the owning key had no credits or was revoked. Skipped checks are never charged."
          },
          "trigger": {
            "type": "string",
            "enum": [
              "scheduled",
              "manual"
            ]
          },
          "scheduled_for": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "estimated_credits": {
            "type": "integer",
            "nullable": true,
            "description": "Upper bound, computed when the check was queued."
          },
          "actual_credits": {
            "type": "integer",
            "description": "What the check was charged: pages fetched at the `/scrape` rate, plus pages judged."
          },
          "summary": {
            "$ref": "#/components/schemas/MonitorSummary"
          },
          "target_results": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object"
            },
            "description": "Per target: pages checked, and for crawls whether the crawl ran to completion. Only a complete crawl can report removed pages."
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Why the check is partial, failed or skipped, or what it could not do."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MonitorCheckListData": {
        "type": "object",
        "properties": {
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonitorCheckData"
            }
          },
          "total": {
            "type": "integer"
          },
          "next": {
            "type": "string",
            "nullable": true,
            "description": "URL for the next page of checks, or null."
          }
        }
      },
      "MonitorJudgment": {
        "type": "object",
        "properties": {
          "meaningful": {
            "type": "boolean"
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "reason": {
            "type": "string",
            "example": "The Starter plan's price went from $19 to $24 a month."
          },
          "meaningful_changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "added",
                    "removed",
                    "changed"
                  ]
                },
                "before": {
                  "type": "string",
                  "nullable": true
                },
                "after": {
                  "type": "string",
                  "nullable": true
                },
                "reason": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "MonitorDiffHunk": {
        "type": "object",
        "properties": {
          "old_start": {
            "type": "integer"
          },
          "old_lines": {
            "type": "integer"
          },
          "new_start": {
            "type": "integer"
          },
          "new_lines": {
            "type": "integer"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "added",
                    "removed",
                    "context"
                  ]
                },
                "content": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "MonitorDiff": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "nullable": true,
            "description": "Markdown mode: a unified diff of the page's markdown.",
            "example": "--- previous\n+++ current\n@@ -3,3 +3,3 @@\n-Starter — $19/mo\n+Starter — $24/mo\n"
          },
          "hunks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonitorDiffHunk"
            },
            "description": "Markdown mode: the same diff as structured hunks."
          },
          "added_lines": {
            "type": "integer"
          },
          "removed_lines": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean",
            "description": "The diff was larger than the stored cap. The line counts still cover all of it."
          },
          "too_large": {
            "type": "boolean",
            "description": "The page changed almost entirely, so no line diff was computed."
          },
          "fields": {
            "type": "object",
            "description": "JSON mode: changed fields keyed by JSON path, each `{ previous, current, change }`.",
            "example": {
              "plans[0].price": {
                "previous": "$19/mo",
                "current": "$24/mo",
                "change": "changed"
              }
            }
          },
          "changed_fields": {
            "type": "integer"
          },
          "fields_truncated": {
            "type": "boolean"
          }
        }
      },
      "MonitorCheckPage": {
        "type": "object",
        "properties": {
          "target_id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "same",
              "new",
              "changed",
              "removed",
              "error"
            ]
          },
          "status_code": {
            "type": "integer",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "previous_check_id": {
            "type": "string",
            "nullable": true,
            "description": "The check the compared snapshot was taken in."
          },
          "is_meaningful": {
            "type": "boolean",
            "nullable": true,
            "description": "The judge's verdict, or `null` when the page was not judged."
          },
          "judgment": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MonitorJudgment"
              }
            ],
            "nullable": true
          },
          "diff": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MonitorDiff"
              }
            ],
            "nullable": true,
            "description": "For changed pages, and for pages that are new since the first check."
          },
          "snapshot": {
            "type": "object",
            "nullable": true,
            "properties": {
              "json": {
                "type": "object",
                "nullable": true
              },
              "search": {
                "type": "object",
                "description": "Search targets: the search that returned the result, and what it said about it.",
                "properties": {
                  "query": {
                    "type": "string"
                  },
                  "position": {
                    "type": "integer",
                    "nullable": true
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "date": {
                    "type": "string",
                    "nullable": true
                  },
                  "source": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            },
            "description": "JSON mode: the full current extraction. Search targets: the search result."
          }
        }
      },
      "MonitorCheckDetailData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MonitorCheckData"
          },
          {
            "type": "object",
            "properties": {
              "notifications": {
                "type": "object",
                "properties": {
                  "webhook": {
                    "type": "object",
                    "nullable": true,
                    "description": "Webhook deliveries for this check, by outcome. `null` when the monitor has no webhook.",
                    "properties": {
                      "pending": {
                        "type": "integer"
                      },
                      "delivered": {
                        "type": "integer"
                      },
                      "failed": {
                        "type": "integer"
                      }
                    }
                  },
                  "email": {
                    "type": "object",
                    "nullable": true,
                    "description": "Alert emails for this check, by outcome. `null` when the monitor emails nobody.",
                    "properties": {
                      "pending": {
                        "type": "integer"
                      },
                      "sent": {
                        "type": "integer"
                      },
                      "failed": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "pages": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MonitorCheckPage"
                }
              },
              "next": {
                "type": "string",
                "nullable": true,
                "description": "URL for the next page of results, or null."
              }
            }
          }
        ]
      },
      "MonitorPageEvent": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Delivery id, also sent as `X-Prefetch-Delivery`. Stable across retries — use it to de-duplicate.",
            "example": "whd_5c1e9a2b7d3f4e6a8b0c2d4e6f8a1b3c"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "monitor_id": {
            "type": "string"
          },
          "monitor_name": {
            "type": "string"
          },
          "check_id": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "description": "The `metadata` you set on the webhook."
          },
          "type": {
            "type": "string",
            "enum": [
              "monitor.page"
            ]
          },
          "data": {
            "$ref": "#/components/schemas/MonitorCheckPage"
          }
        }
      },
      "MonitorCheckCompletedEvent": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "`true` only for a `completed` check."
          },
          "id": {
            "type": "string",
            "description": "Delivery id, also sent as `X-Prefetch-Delivery`. Stable across retries — use it to de-duplicate.",
            "example": "whd_5c1e9a2b7d3f4e6a8b0c2d4e6f8a1b3c"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "monitor_id": {
            "type": "string"
          },
          "monitor_name": {
            "type": "string"
          },
          "check_id": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "description": "The `metadata` you set on the webhook."
          },
          "type": {
            "type": "string",
            "enum": [
              "monitor.check.completed"
            ]
          },
          "data": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "queued",
                  "running",
                  "completed",
                  "failed",
                  "partial",
                  "skipped_overlap",
                  "skipped_no_credits"
                ]
              },
              "trigger": {
                "type": "string",
                "enum": [
                  "scheduled",
                  "manual"
                ]
              },
              "summary": {
                "$ref": "#/components/schemas/MonitorSummary"
              },
              "started_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "finished_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "actual_credits": {
                "type": "integer"
              },
              "error": {
                "type": "string",
                "nullable": true
              }
            }
          }
        }
      },
      "SearchData": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "web",
              "news"
            ]
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchResultItem"
            }
          },
          "count": {
            "type": "number"
          },
          "scraped": {
            "type": "number",
            "description": "Result pages fetched — each charged at the /scrape rate."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "query",
          "type",
          "results",
          "count",
          "scraped",
          "warnings"
        ]
      },
      "SearchResultItem": {
        "type": "object",
        "properties": {
          "position": {
            "type": "number",
            "description": "Rank on the results page, from 1.",
            "example": 1
          },
          "url": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "The snippet the search engine shows for the result."
          },
          "date": {
            "type": "string",
            "nullable": true,
            "description": "Publication date as the result shows it, when it shows one.",
            "example": "2 days ago"
          },
          "source": {
            "type": "string",
            "nullable": true,
            "description": "News results: the publisher.",
            "example": "The Verge"
          },
          "image_url": {
            "type": "string",
            "nullable": true,
            "description": "News results: the article's thumbnail."
          },
          "scrape": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ScrapeData"
              },
              {
                "description": "The result page in the requested formats — the same object GET /scrape returns. Present when scraping was asked for and the page was fetched."
              }
            ]
          },
          "scrape_error": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string"
              },
              "error_code": {
                "type": "string",
                "enum": [
                  "INVALID_REQUEST",
                  "PAYLOAD_TOO_LARGE",
                  "NOT_FOUND",
                  "CONFLICT",
                  "UNAUTHORIZED",
                  "FORBIDDEN",
                  "CREDITS_EXHAUSTED",
                  "RATE_LIMITED",
                  "CONCURRENCY_LIMITED",
                  "URL_BLOCKED",
                  "URL_NOT_PERMITTED",
                  "DNS_RESOLUTION_FAILED",
                  "TARGET_BLOCKED",
                  "TARGET_CONNECTION_FAILED",
                  "TARGET_TIMEOUT",
                  "TARGET_SSL_ERROR",
                  "TARGET_SERVER_ERROR",
                  "TARGET_CLIENT_ERROR",
                  "TARGET_NOT_A_PAGE",
                  "NO_LINKS_FOUND",
                  "TARGET_UNLOADABLE",
                  "TARGET_ELEMENT_NOT_FOUND",
                  "RESEARCH_INCONCLUSIVE",
                  "TIMEOUT",
                  "SERVICE_BUSY",
                  "SERVICE_UNAVAILABLE",
                  "INTERNAL_ERROR"
                ]
              }
            },
            "required": [
              "error",
              "error_code"
            ],
            "description": "Why the result page could not be scraped. Not charged."
          }
        },
        "required": [
          "position",
          "url",
          "title",
          "description",
          "date",
          "source",
          "image_url"
        ]
      },
      "SearchBody": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "What to search for, as you would type it into Google (1–400 characters). Search operators work (`\"exact phrase\"`, `-word`, `filetype:pdf`). `q` is accepted too.",
            "example": "best open source CRM"
          },
          "limit": {
            "type": "integer",
            "description": "Results to return (1–50; 1–10 when results are scraped). Default: 10.",
            "example": 5
          },
          "type": {
            "type": "string",
            "enum": [
              "web",
              "news"
            ]
          },
          "country": {
            "type": "string"
          },
          "language": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "time_range": {
            "type": "string",
            "enum": [
              "hour",
              "day",
              "week",
              "month",
              "year"
            ]
          },
          "include_domains": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "exclude_domains": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scrape_options": {
            "type": "object",
            "properties": {
              "formats": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "markdown",
                    "summary",
                    "html",
                    "raw_html",
                    "links",
                    "images",
                    "json",
                    "screenshot"
                  ]
                }
              },
              "only_main_content": {
                "type": "boolean"
              },
              "include_links": {
                "type": "boolean"
              },
              "include_images": {
                "type": "boolean"
              },
              "include_base64_images": {
                "type": "boolean"
              },
              "include_selectors": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "exclude_selectors": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "json_prompt": {
                "type": "string"
              },
              "json_schema": {
                "type": "object",
                "additionalProperties": {
                  "nullable": true
                }
              },
              "summary_max_words": {
                "type": "integer"
              },
              "screenshot_full_page": {
                "type": "boolean"
              },
              "screenshot_format": {
                "type": "string",
                "enum": [
                  "jpeg",
                  "png",
                  "webp"
                ]
              },
              "wait_for": {
                "type": "integer"
              },
              "wait_for_selector": {
                "type": "string"
              },
              "headers": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "mobile": {
                "type": "boolean"
              },
              "max_age": {
                "type": "integer"
              },
              "store_in_cache": {
                "type": "boolean"
              },
              "check_prompt_injection": {
                "type": "boolean",
                "description": "Check each page for prompt injection, as on /scrape. Adds the AI surcharge to every page."
              }
            },
            "description": "Scrape each result page — the same options /scrape takes. Omit to return search results only."
          },
          "timeout": {
            "type": "integer",
            "description": "Give up after this many milliseconds (5,000–45000). Result pages still loading are returned with a `scrape_error` and not charged."
          }
        },
        "required": [
          "query"
        ],
        "description": "The same options as GET /search, as typed JSON."
      },
      "StyleguideData": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "domain": {
            "type": "string",
            "example": "stripe.com"
          },
          "dark_mode": {
            "type": "boolean"
          },
          "styleguide": {
            "$ref": "#/components/schemas/Styleguide"
          },
          "exports": {
            "type": "object",
            "properties": {
              "css": {
                "type": "string",
                "description": "The guide as CSS custom properties on `:root`.",
                "example": ":root {\n  --color-primary: #635BFF;\n}\n"
              },
              "tailwind": {
                "type": "object",
                "additionalProperties": {
                  "nullable": true
                },
                "description": "The guide as a Tailwind config: merge `theme.extend` into yours."
              }
            },
            "required": [
              "css",
              "tailwind"
            ]
          }
        },
        "required": [
          "url",
          "domain",
          "dark_mode",
          "styleguide",
          "exports"
        ]
      },
      "Styleguide": {
        "type": "object",
        "properties": {
          "color_scheme": {
            "type": "string",
            "nullable": true,
            "enum": [
              "light",
              "dark",
              null
            ]
          },
          "colors": {
            "type": "object",
            "properties": {
              "primary": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF",
                "description": "The main action color: the fill of the most prominent button."
              },
              "secondary": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "accent": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "background": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "surface": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF",
                "description": "The most used fill other than the page background: panels, cards, sections."
              },
              "text": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "text_muted": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "heading": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "link": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              },
              "border": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              }
            },
            "required": [
              "primary",
              "secondary",
              "accent",
              "background",
              "surface",
              "text",
              "text_muted",
              "heading",
              "link",
              "border"
            ]
          },
          "palette": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "hex": {
                  "type": "string"
                },
                "role": {
                  "type": "string"
                }
              },
              "required": [
                "hex",
                "role"
              ]
            },
            "description": "Every color the guide found, by role, most important first (up to 16)."
          },
          "typography": {
            "type": "object",
            "properties": {
              "font_families": {
                "type": "object",
                "properties": {
                  "heading": {
                    "$ref": "#/components/schemas/FontFamilyRef"
                  },
                  "body": {
                    "$ref": "#/components/schemas/FontFamilyRef"
                  },
                  "mono": {
                    "$ref": "#/components/schemas/FontFamilyRef"
                  }
                },
                "required": [
                  "heading",
                  "body",
                  "mono"
                ]
              },
              "styles": {
                "type": "object",
                "properties": {
                  "h1": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "h2": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "h3": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "h4": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "h5": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "h6": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "body": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "small": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "label": {
                    "$ref": "#/components/schemas/TextStyle"
                  },
                  "nav": {
                    "$ref": "#/components/schemas/TextStyle"
                  }
                },
                "required": [
                  "h1",
                  "h2",
                  "h3",
                  "h4",
                  "h5",
                  "h6",
                  "body",
                  "small",
                  "label",
                  "nav"
                ],
                "description": "The style most of each element's instances share."
              },
              "base_font_size": {
                "type": "string",
                "nullable": true,
                "example": "16px"
              },
              "scale": {
                "type": "object",
                "nullable": true,
                "properties": {
                  "ratio": {
                    "type": "number",
                    "example": 1.25
                  },
                  "name": {
                    "type": "string",
                    "nullable": true,
                    "example": "major third"
                  }
                },
                "required": [
                  "ratio",
                  "name"
                ],
                "description": "The ratio between steps of the type scale, named when it is a classic one."
              },
              "web_fonts": {
                "type": "object",
                "properties": {
                  "google_fonts": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "adobe_fonts": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "google_fonts",
                  "adobe_fonts"
                ],
                "description": "Stylesheet URLs that load the fonts, to reuse as they are."
              }
            },
            "required": [
              "font_families",
              "styles",
              "base_font_size",
              "scale",
              "web_fonts"
            ]
          },
          "spacing": {
            "type": "object",
            "properties": {
              "base_unit": {
                "type": "string",
                "nullable": true,
                "description": "The unit most margins, paddings and gaps are a multiple of.",
                "example": "8px"
              },
              "scale": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "example": [
                  "4px",
                  "8px",
                  "16px",
                  "24px",
                  "32px",
                  "48px"
                ]
              }
            },
            "required": [
              "base_unit",
              "scale"
            ]
          },
          "radius": {
            "type": "object",
            "properties": {
              "small": {
                "type": "string",
                "nullable": true
              },
              "medium": {
                "type": "string",
                "nullable": true
              },
              "large": {
                "type": "string",
                "nullable": true
              },
              "full": {
                "type": "boolean",
                "description": "Whether pills (fully rounded corners) are used."
              },
              "scale": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "button": {
                "type": "string",
                "nullable": true
              },
              "input": {
                "type": "string",
                "nullable": true
              },
              "card": {
                "type": "string",
                "nullable": true
              }
            },
            "required": [
              "small",
              "medium",
              "large",
              "full",
              "scale",
              "button",
              "input",
              "card"
            ]
          },
          "shadows": {
            "type": "object",
            "properties": {
              "small": {
                "type": "string",
                "nullable": true
              },
              "medium": {
                "type": "string",
                "nullable": true
              },
              "large": {
                "type": "string",
                "nullable": true
              },
              "scale": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "small",
              "medium",
              "large",
              "scale"
            ]
          },
          "borders": {
            "type": "object",
            "properties": {
              "width": {
                "type": "string",
                "nullable": true
              },
              "color": {
                "type": "string",
                "nullable": true,
                "example": "#635BFF"
              }
            },
            "required": [
              "width",
              "color"
            ]
          },
          "components": {
            "type": "object",
            "properties": {
              "button_primary": {
                "$ref": "#/components/schemas/StyleguideButton"
              },
              "button_secondary": {
                "$ref": "#/components/schemas/StyleguideButton"
              },
              "input": {
                "type": "object",
                "nullable": true,
                "properties": {
                  "background": {
                    "type": "string",
                    "nullable": true,
                    "example": "#635BFF"
                  },
                  "text_color": {
                    "type": "string",
                    "nullable": true,
                    "example": "#635BFF"
                  },
                  "border_color": {
                    "type": "string",
                    "nullable": true,
                    "example": "#635BFF"
                  },
                  "border_radius": {
                    "type": "string",
                    "nullable": true
                  },
                  "height": {
                    "type": "string",
                    "nullable": true
                  },
                  "padding": {
                    "type": "string",
                    "nullable": true
                  },
                  "font_size": {
                    "type": "string",
                    "nullable": true
                  }
                },
                "required": [
                  "background",
                  "text_color",
                  "border_color",
                  "border_radius"
                ]
              },
              "card": {
                "type": "object",
                "nullable": true,
                "properties": {
                  "background": {
                    "type": "string",
                    "nullable": true,
                    "example": "#635BFF"
                  },
                  "border_color": {
                    "type": "string",
                    "nullable": true,
                    "example": "#635BFF"
                  },
                  "border_width": {
                    "type": "string",
                    "nullable": true
                  },
                  "border_radius": {
                    "type": "string",
                    "nullable": true
                  },
                  "box_shadow": {
                    "type": "string",
                    "nullable": true
                  },
                  "padding": {
                    "type": "string",
                    "nullable": true
                  }
                },
                "required": [
                  "background",
                  "border_color",
                  "border_width",
                  "border_radius",
                  "box_shadow",
                  "padding"
                ]
              },
              "link": {
                "type": "object",
                "nullable": true,
                "properties": {
                  "color": {
                    "type": "string",
                    "nullable": true,
                    "example": "#635BFF"
                  },
                  "text_decoration": {
                    "type": "string",
                    "nullable": true
                  },
                  "font_weight": {
                    "type": "number",
                    "nullable": true
                  }
                },
                "required": [
                  "color",
                  "text_decoration",
                  "font_weight"
                ]
              }
            },
            "required": [
              "button_primary",
              "button_secondary",
              "input",
              "card",
              "link"
            ]
          },
          "breakpoints": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The media-query widths the site's CSS switches layout at.",
            "example": [
              "640px",
              "768px",
              "1024px",
              "1280px"
            ]
          },
          "css_variables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The site's own CSS custom properties for colors, lengths, fonts and shadows, as set on the root (up to 120).",
            "example": {
              "--brand-primary": "#635BFF",
              "--radius-md": "8px"
            }
          }
        },
        "required": [
          "color_scheme",
          "colors",
          "palette",
          "typography",
          "spacing",
          "radius",
          "shadows",
          "borders",
          "components",
          "breakpoints",
          "css_variables"
        ]
      },
      "TextStyle": {
        "type": "object",
        "nullable": true,
        "properties": {
          "font_family": {
            "type": "string",
            "nullable": true,
            "example": "Inter"
          },
          "font_size": {
            "type": "string",
            "nullable": true,
            "example": "48px"
          },
          "font_weight": {
            "type": "number",
            "nullable": true,
            "example": 600
          },
          "line_height": {
            "type": "string",
            "nullable": true,
            "example": "56px"
          },
          "letter_spacing": {
            "type": "string",
            "nullable": true,
            "example": "-0.96px"
          },
          "text_transform": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "font_family",
          "font_size",
          "font_weight",
          "line_height",
          "letter_spacing",
          "text_transform"
        ]
      },
      "FontFamilyRef": {
        "type": "object",
        "nullable": true,
        "properties": {
          "family": {
            "type": "string",
            "example": "Inter"
          },
          "stack": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "Inter",
              "system-ui",
              "sans-serif"
            ]
          }
        },
        "required": [
          "family",
          "stack"
        ]
      },
      "StyleguideButton": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ButtonTokens"
          },
          {
            "type": "object",
            "nullable": true,
            "properties": {
              "font_family": {
                "type": "string",
                "nullable": true
              },
              "font_size": {
                "type": "string",
                "nullable": true
              },
              "height": {
                "type": "string",
                "nullable": true,
                "example": "40px"
              },
              "padding": {
                "type": "string",
                "nullable": true,
                "example": "10px 20px"
              },
              "text_transform": {
                "type": "string",
                "nullable": true
              },
              "letter_spacing": {
                "type": "string",
                "nullable": true
              },
              "box_shadow": {
                "type": "string",
                "nullable": true
              }
            }
          }
        ]
      },
      "TransactionData": {
        "type": "object",
        "properties": {
          "descriptor": {
            "type": "string",
            "example": "SQ *BLUE BOTTLE COFFE OAKLAND CA"
          },
          "kind": {
            "type": "string",
            "enum": [
              "merchant",
              "person",
              "transfer",
              "fee",
              "atm",
              "refund",
              "unknown"
            ],
            "description": "What the line is: a payment to a `merchant`, to a `person` (Venmo, Zelle…), a `transfer` between accounts, a bank `fee`, an `atm` withdrawal, a `refund`, or `unknown`."
          },
          "merchant": {
            "type": "object",
            "nullable": true,
            "properties": {
              "name": {
                "type": "string",
                "nullable": true,
                "description": "The merchant's trading name, with words the descriptor truncated completed.",
                "example": "Blue Bottle Coffee"
              },
              "domain": {
                "type": "string",
                "nullable": true,
                "description": "Its website, when found with enough confidence; ready for every other endpoint's `url`.",
                "example": "bluebottlecoffee.com"
              },
              "url": {
                "type": "string",
                "nullable": true
              },
              "confidence": {
                "type": "number",
                "nullable": true,
                "description": "0–1, for the domain. At 0.8 or above treat it as the answer.",
                "example": 0.93
              },
              "source": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "curated",
                  "index",
                  "live",
                  null
                ]
              }
            },
            "required": [
              "name",
              "domain",
              "url",
              "confidence",
              "source"
            ],
            "description": "Null unless `kind` is `merchant`."
          },
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ResolveResultItem"
            },
            "description": "Every domain considered, best first — including ones below the confidence bar."
          },
          "payment_processor": {
            "type": "string",
            "nullable": true,
            "description": "The processor or wallet that prefixed the line (Square, Toast, PayPal…).",
            "example": "Square"
          },
          "location": {
            "type": "object",
            "properties": {
              "city": {
                "type": "string",
                "nullable": true
              },
              "region": {
                "type": "string",
                "nullable": true
              },
              "country": {
                "type": "string",
                "nullable": true
              }
            },
            "required": [
              "city",
              "region",
              "country"
            ],
            "description": "Where the line says the payment was made, when it says.",
            "example": {
              "city": "Oakland",
              "region": "CA",
              "country": "US"
            }
          },
          "category": {
            "type": "string",
            "nullable": true,
            "example": "Coffee shop"
          },
          "logo_url": {
            "type": "string",
            "nullable": true,
            "description": "The merchant's logo on the Prefetch logo CDN, with your publishable token: put it straight in an <img>. Null when no website was found."
          },
          "brand": {
            "type": "object",
            "properties": {
              "colors": {
                "$ref": "#/components/schemas/ColorsBlock"
              },
              "fonts": {
                "type": "object",
                "properties": {
                  "families": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "families"
                ],
                "example": {
                  "families": [
                    "Inter",
                    "Roboto"
                  ]
                }
              },
              "logos": {
                "$ref": "#/components/schemas/LogosBlock"
              },
              "images": {
                "$ref": "#/components/schemas/ImagesBlock"
              },
              "design_tokens": {
                "$ref": "#/components/schemas/DesignTokens"
              },
              "social_links": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                },
                "example": {
                  "twitter": "https://twitter.com/stripe",
                  "linkedin": "https://linkedin.com/company/stripe"
                }
              }
            },
            "description": "With `include_brand=true` and a website found: the same block GET /brand returns."
          },
          "parsed_by": {
            "type": "string",
            "enum": [
              "model",
              "rules"
            ],
            "description": "`rules` when the language model was unavailable and the line was read by pattern alone."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "descriptor",
          "kind",
          "merchant",
          "candidates",
          "payment_processor",
          "location",
          "category",
          "logo_url",
          "parsed_by",
          "warnings"
        ]
      },
      "TransactionBody": {
        "type": "object",
        "properties": {
          "descriptor": {
            "type": "string",
            "description": "The transaction line as the bank statement or card network shows it (1–200 characters).",
            "example": "PAYPAL *SPOTIFYAB"
          },
          "country": {
            "type": "string"
          },
          "mcc": {
            "type": "string"
          },
          "include_brand": {
            "type": "boolean",
            "description": "Also return the merchant's brand — logos, colors, fonts — exactly as GET /brand would, when its website is found. Adds the /brand price (10 credits), charged only when a brand is returned. Can take several seconds for a site not seen before."
          }
        },
        "required": [
          "descriptor"
        ],
        "description": "The same options as GET /transaction, as typed JSON."
      },
      "BatchBody": {
        "type": "object",
        "properties": {
          "urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The URLs or bare domains to run (1–500). Duplicates run once. `domains` is accepted too.",
            "example": [
              "stripe.com",
              "https://linear.app",
              "notion.so"
            ]
          },
          "options": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "description": "The endpoint's own parameters, as GET /{endpoint} takes them, applied to every URL — e.g. `{\"design_tokens\": true}` for brand or enrich, `{\"device\": \"iphone_15\"}` for screenshot. Typed JSON or strings.",
            "example": {
              "design_tokens": true
            }
          },
          "concurrency": {
            "type": "integer",
            "description": "URLs run in parallel (1–5). Default: 2. Batches of brand, enrich, screenshot and styleguide run at most 3 at a time, and default to 3."
          },
          "ignore_invalid_urls": {
            "type": "boolean",
            "description": "Drop URLs that fail validation (listed in `invalid_urls`) instead of rejecting the whole batch. Default: false."
          },
          "webhook": {
            "$ref": "#/components/schemas/CrawlWebhook"
          }
        },
        "required": [
          "urls"
        ]
      },
      "CrawlWebhook": {
        "anyOf": [
          {
            "type": "string",
            "description": "An https:// URL; every event is sent."
          },
          {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "example": "https://example.com/hooks/prefetch"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "started",
                    "page",
                    "completed",
                    "failed"
                  ]
                },
                "description": "Which events to send. Default: all four."
              },
              "headers": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                },
                "description": "Sent with every delivery (up to 20)."
              },
              "metadata": {
                "type": "object",
                "additionalProperties": {
                  "nullable": true
                },
                "description": "Echoed back in every payload (up to 4 KB)."
              }
            },
            "required": [
              "url"
            ]
          }
        ],
        "description": "Where to send progress. Each delivery is signed — `X-Prefetch-Signature: t=<unix>,v1=<hex>`, HMAC-SHA256 of `<t>.<raw body>` with the `secret` returned when the job is created — the same scheme as monitor webhooks."
      },
      "BatchStatusData": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CrawlStatusData"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BatchItem"
                },
                "description": "Answered URLs, in completion order."
              }
            }
          }
        ]
      },
      "BatchItem": {
        "allOf": [
          {
            "type": "object",
            "properties": {
              "url": {
                "type": "string"
              },
              "depth": {
                "type": "number",
                "description": "Always 0: a batch follows nothing."
              },
              "status_code": {
                "type": "number",
                "nullable": true
              },
              "ok": {
                "type": "boolean",
                "description": "False when the URL could not be answered. You are not charged for it."
              },
              "error": {
                "type": "string",
                "nullable": true
              },
              "error_code": {
                "type": "string",
                "nullable": true,
                "description": "Why the page failed, as one of the API's error codes (`TARGET_TIMEOUT`, `DNS_RESOLUTION_FAILED`, …); null when it did not.",
                "example": "TARGET_SERVER_ERROR"
              }
            },
            "required": [
              "url",
              "depth",
              "status_code",
              "ok",
              "error",
              "error_code"
            ]
          },
          {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            }
          }
        ],
        "description": "One URL of a batch: the fields GET /{endpoint} returns for it (`domain`, `brand`, `company`, `classification`, `screenshot_url`, `styleguide`, …), plus the batch's bookkeeping."
      },
      "LogoTokenData": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "Your organisation's publishable logo token. Safe to put in a web page: it serves logo images only, within your plan's quota.",
            "example": "pk_4f1c9e2b7a0d4c3e8b6a1f2d3c4b5a69"
          },
          "cdn_url": {
            "type": "string",
            "example": "https://logo.prefetch.io"
          },
          "example": {
            "type": "string",
            "example": "https://logo.prefetch.io/stripe.com?token=pk_4f1c9e2b7a0d4c3e8b6a1f2d3c4b5a69"
          },
          "quota": {
            "type": "number",
            "nullable": true,
            "description": "Logo requests included this month; null is unlimited.",
            "example": 100000
          },
          "used": {
            "type": "number",
            "description": "Logo requests counted this month. Counts reach it within a minute or so.",
            "example": 1234
          },
          "period": {
            "type": "string",
            "nullable": true,
            "description": "The month the counts are for (its first day, UTC).",
            "example": "2026-10-01"
          }
        },
        "required": [
          "token",
          "cdn_url",
          "example",
          "quota",
          "used",
          "period"
        ]
      }
    },
    "parameters": {
      "url": {
        "name": "url",
        "in": "query",
        "required": true,
        "description": "The website URL to process. `https://` is prepended automatically if no protocol is provided.",
        "schema": {
          "type": "string",
          "example": "https://stripe.com"
        }
      },
      "screenshotWidth": {
        "name": "width",
        "in": "query",
        "required": false,
        "description": "Viewport width in pixels. Range: 320–2560. Default: 1440.",
        "schema": {
          "type": "integer",
          "minimum": 320,
          "maximum": 2560,
          "default": 1440
        }
      },
      "screenshotHeight": {
        "name": "height",
        "in": "query",
        "required": false,
        "description": "Viewport height in pixels. Range: 240–5000. Default: 900.",
        "schema": {
          "type": "integer",
          "minimum": 240,
          "maximum": 5000,
          "default": 900
        }
      },
      "screenshotFormat": {
        "name": "format",
        "in": "query",
        "required": false,
        "description": "Output format: `jpeg`, `png`, `webp`, or `pdf` (the whole page as a PDF document). Default: `jpeg`.",
        "schema": {
          "type": "string",
          "enum": ["jpeg", "png", "webp", "pdf"],
          "default": "jpeg"
        }
      },
      "screenshotFullPage": {
        "name": "full_page",
        "in": "query",
        "required": false,
        "description": "Capture full scrollable page height. Default: `false`.",
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "scrapeFormats": {
        "name": "formats",
        "in": "query",
        "required": false,
        "description": "Comma-separated list of output formats: `markdown`, `summary`, `html`, `raw_html`, `links`, `images`, `json`, `screenshot`. Each requested format appears as its own object on `data`; formats you do not request are absent, not null.",
        "schema": {
          "type": "string",
          "default": "markdown",
          "example": "markdown,links"
        }
      },
      "onlyMainContent": {
        "name": "only_main_content",
        "in": "query",
        "required": false,
        "description": "Strip navigation, sidebars, footers, and cookie banners before rendering `markdown`, `html`, `summary`, and `json`. `links` and `images` always come from the full document.",
        "schema": {
          "type": "boolean",
          "default": true
        }
      },
      "includeLinks": {
        "name": "include_links",
        "in": "query",
        "required": false,
        "description": "Keep hyperlinks in the `markdown` and `html` output. When false, link text is kept and the target is dropped.",
        "schema": {
          "type": "boolean",
          "default": true
        }
      },
      "includeImages": {
        "name": "include_images",
        "in": "query",
        "required": false,
        "description": "Keep images in the `markdown` and `html` output.",
        "schema": {
          "type": "boolean",
          "default": true
        }
      },
      "includeBase64Images": {
        "name": "include_base64_images",
        "in": "query",
        "required": false,
        "description": "Keep inline `data:` images. Off by default because base64 payloads are large and carry no meaning as text.",
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "includeSelectors": {
        "name": "include_selectors",
        "in": "query",
        "required": false,
        "description": "Comma-separated CSS selectors to keep. Overrides main-content detection entirely.",
        "schema": {
          "type": "string",
          "example": "article,.post-body"
        }
      },
      "excludeSelectors": {
        "name": "exclude_selectors",
        "in": "query",
        "required": false,
        "description": "Comma-separated CSS selectors to remove before rendering.",
        "schema": {
          "type": "string",
          "example": ".cookie-bar,#promo"
        }
      },
      "jsonPrompt": {
        "name": "json_prompt",
        "in": "query",
        "required": false,
        "description": "What to extract, in plain language. Required for the `json` format unless `json_schema` is given.",
        "schema": {
          "type": "string",
          "example": "product name, price and availability"
        }
      },
      "jsonSchema": {
        "name": "json_schema",
        "in": "query",
        "required": false,
        "description": "A JSON Schema, passed as a JSON string, describing the object the `json` format should return.",
        "schema": {
          "type": "string"
        }
      },
      "summaryMaxWords": {
        "name": "summary_max_words",
        "in": "query",
        "required": false,
        "description": "Word budget for the `summary` format.",
        "schema": {
          "type": "integer",
          "minimum": 20,
          "maximum": 400,
          "default": 120
        }
      },
      "scrapeScreenshotFullPage": {
        "name": "screenshot_full_page",
        "in": "query",
        "required": false,
        "description": "For the `screenshot` format: capture the whole scrollable page.",
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "screenshotFormatParam": {
        "name": "screenshot_format",
        "in": "query",
        "required": false,
        "description": "For the `screenshot` format: image type.",
        "schema": {
          "type": "string",
          "enum": [
            "jpeg",
            "png",
            "webp"
          ],
          "default": "jpeg"
        }
      },
      "waitFor": {
        "name": "wait_for",
        "in": "query",
        "required": false,
        "description": "Milliseconds to wait after the page loads, for content that arrives late. Renders in a browser.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "maximum": 30000,
          "default": 0
        }
      },
      "waitForSelector": {
        "name": "wait_for_selector",
        "in": "query",
        "required": false,
        "description": "Wait (up to 10 s) for this CSS selector before reading the page. Best effort: if it never appears, the page is returned with a warning.",
        "schema": {
          "type": "string",
          "example": "#pricing-table"
        }
      },
      "scrapeHeaders": {
        "name": "headers",
        "in": "query",
        "required": false,
        "description": "Request headers to send to the target, as a JSON object string. Up to 20; hop-by-hop and proxy headers are refused. Requests with headers are never cached. Easier as an object in `POST /scrape`.",
        "schema": {
          "type": "string",
          "example": "{\"Accept-Language\":\"de-DE\"}"
        }
      },
      "mobile": {
        "name": "mobile",
        "in": "query",
        "required": false,
        "description": "Render the page as a phone (viewport, touch and user agent).",
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "scrapeTimeout": {
        "name": "timeout",
        "in": "query",
        "required": false,
        "description": "Give up after this many milliseconds.",
        "schema": {
          "type": "integer",
          "minimum": 5000,
          "maximum": 50000,
          "default": 50000
        }
      },
      "maxAge": {
        "name": "max_age",
        "in": "query",
        "required": false,
        "description": "Accept a stored copy of the page fetched at most this many milliseconds ago instead of fetching it again (up to 30 days). Any mix of formats is served from one stored fetch; `metadata.cache_state` says which happened. 0 always fetches.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2592000000,
          "default": 0
        }
      },
      "storeInCache": {
        "name": "store_in_cache",
        "in": "query",
        "required": false,
        "description": "Store this fetch for later `max_age` requests.",
        "schema": {
          "type": "boolean",
          "default": true
        }
      },
      "checkPromptInjection": {
        "name": "check_prompt_injection",
        "in": "query",
        "required": false,
        "description": "Check the page's text for prompt injection — text written to make an AI model reading the page ignore its instructions, leak data or take actions — and report it in `prompt_injection`. The page is still returned: the check warns, it does not block. Costs the same 3-credit surcharge as `summary` and `json` (once per page, however many of the three you ask for).",
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "mapLimit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Maximum number of links to return.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 1000
        }
      },
      "mapSearch": {
        "name": "search",
        "in": "query",
        "required": false,
        "description": "Rank and filter results by relevance to this query. Links that match nothing are dropped.",
        "schema": {
          "type": "string",
          "example": "pricing"
        }
      },
      "mapSitemap": {
        "name": "sitemap",
        "in": "query",
        "required": false,
        "description": "Which sources to use. `include` merges sitemap entries with on-page links, `skip` uses on-page links only, `only` uses sitemaps only.",
        "schema": {
          "type": "string",
          "enum": [
            "include",
            "skip",
            "only"
          ],
          "default": "include"
        }
      },
      "mapIncludeSubdomains": {
        "name": "include_subdomains",
        "in": "query",
        "required": false,
        "description": "Include links on subdomains of the target.",
        "schema": {
          "type": "boolean",
          "default": true
        }
      },
      "mapIgnoreQueryParams": {
        "name": "ignore_query_params",
        "in": "query",
        "required": false,
        "description": "Treat URLs that differ only by query string as one page.",
        "schema": {
          "type": "boolean",
          "default": true
        }
      },
      "crawlId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The crawl id returned by `POST /crawl`.",
        "schema": {
          "type": "string",
          "example": "crw_9f2c1a7b4e0d4c3a8b1e5f7d2c9a0b3e"
        }
      },
      "crawlSkip": {
        "name": "skip",
        "in": "query",
        "required": false,
        "description": "Number of result pages to skip. Use the `next` link rather than building this by hand.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "default": 0
        }
      },
      "crawlPageLimit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Number of crawled pages to return per request.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "monitorId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The monitor id returned by `POST /monitor`.",
        "schema": {
          "type": "string",
          "example": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c"
        }
      },
      "monitorCheckId": {
        "name": "checkId",
        "in": "path",
        "required": true,
        "description": "A check id, from `GET /monitor/{id}/checks` or `POST /monitor/{id}/run`.",
        "schema": {
          "type": "string",
          "example": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a"
        }
      },
      "monitorListLimit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Items to return per request.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "monitorListOffset": {
        "name": "offset",
        "in": "query",
        "required": false,
        "description": "Items to skip. Use the `next` link rather than building this by hand.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "default": 0
        }
      },
      "monitorCheckStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Only checks with this status.",
        "schema": {
          "type": "string",
          "enum": [
            "queued",
            "running",
            "completed",
            "failed",
            "partial",
            "skipped_overlap",
            "skipped_no_credits"
          ]
        }
      },
      "monitorPageSkip": {
        "name": "skip",
        "in": "query",
        "required": false,
        "description": "Page results to skip. Use the `next` link rather than building this by hand.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "default": 0
        }
      },
      "monitorPageLimit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Page results to return per request.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "monitorPageStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Only pages with this status — `changed` to see just what changed.",
        "schema": {
          "type": "string",
          "enum": [
            "same",
            "new",
            "changed",
            "removed",
            "error"
          ]
        }
      }
    }
  },
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Liveness check",
        "description": "Returns HTTP 200 if the server process is alive. No authentication required.",
        "security": [],
        "tags": ["Health"],
        "responses": {
          "200": {
            "description": "Server is alive.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "enum": ["ok"], "example": "ok" },
                    "uptime": { "type": "integer", "example": 3600 },
                    "pid": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ready": {
      "get": {
        "operationId": "getReady",
        "summary": "Readiness check",
        "description": "Returns HTTP 200 if the server is ready to handle requests. Returns HTTP 503 if a dependency is unavailable.",
        "security": [],
        "tags": ["Health"],
        "responses": {
          "200": {
            "description": "Server is ready.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "enum": ["ready", "degraded"], "example": "ready" },
                    "checks": {
                      "type": "object",
                      "properties": {
                        "redis": { "type": "string", "example": "ok" }
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Server is not ready.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "enum": ["degraded"] },
                    "checks": {
                      "type": "object",
                      "properties": {
                        "redis": { "type": "string", "example": "error" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/classify": {
      "get": {
        "operationId": "classifyUrl",
        "summary": "Classify a website",
        "description": "Classifies a website into an IAB content taxonomy category with human-readable descriptions, stock tickers, and ISIN codes. **Credit cost: 5.**",
        "tags": ["Endpoints"],
        "parameters": [
          { "$ref": "#/components/parameters/url" }
        ],
        "responses": {
          "200": {
            "description": "Classification result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "data": { "$ref": "#/components/schemas/ClassifyData" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  },
                  "required": ["success", "data", "meta"]
                },
                "example": {
                  "success": true,
                  "data": {
                    "url": "https://stripe.com",
                    "domain": "stripe.com",
                    "classification": {
                      "iab_id": "IAB3-4",
                      "iab_parent_id": "IAB3",
                      "category": "Business",
                      "subcategory": "Business Software",
                      "description": "Stripe provides payment processing infrastructure for internet businesses.",
                      "tagline_description": "Payment infrastructure for the internet.",
                      "long_description": "Stripe provides payment processing infrastructure for internet businesses, enabling companies to accept payments, manage subscriptions, and handle global commerce operations.",
                      "stock_tickers": [],
                      "isins": []
                    }
                  },
                  "meta": {
                    "requestId": "a3f2c1d4-7b6e-4f2a-9c1d-8e3f2a1b4c5d",
                    "durationMs": 1842
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid or missing URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Revoked key, expired key, credit limit, or blocklisted URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "422": { "description": "URL hostname could not be resolved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "503": { "description": "Service temporarily busy — retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "504": { "description": "Request timed out.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/company": {
      "get": {
        "operationId": "getCompany",
        "summary": "Extract company info",
        "description": "Extracts the legal company name, contact email addresses, and physical addresses from a website. **Credit cost: 5.**",
        "tags": ["Endpoints"],
        "parameters": [
          { "$ref": "#/components/parameters/url" }
        ],
        "responses": {
          "200": {
            "description": "Company information.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "data": { "$ref": "#/components/schemas/CompanyData" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  },
                  "required": ["success", "data", "meta"]
                },
                "example": {
                  "success": true,
                  "data": {
                    "domain": "stripe.com",
                    "url": "https://stripe.com",
                    "company": {
                      "name": "Stripe, Inc.",
                      "emails": ["support@stripe.com"],
                      "addresses": ["354 Oyster Point Blvd, South San Francisco, CA 94080"]
                    }
                  },
                  "meta": {
                    "requestId": "b9e1a2f3-4c5d-6e7f-8a9b-0c1d2e3f4a5b",
                    "durationMs": 3210
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid or missing URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Revoked key, expired key, credit limit, or blocklisted URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "422": { "description": "URL hostname could not be resolved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "503": { "description": "Service temporarily busy — retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "504": { "description": "Request timed out.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/screenshot": {
      "get": {
        "operationId": "takeScreenshot",
        "summary": "Take a screenshot",
        "description": "Captures a screenshot of a webpage and returns a public URL to the image stored in cloud storage. **Credit cost: 1.**",
        "tags": ["Endpoints"],
        "parameters": [
          { "$ref": "#/components/parameters/url" },
          { "$ref": "#/components/parameters/screenshotWidth" },
          { "$ref": "#/components/parameters/screenshotHeight" },
          { "$ref": "#/components/parameters/screenshotFormat" },
          { "$ref": "#/components/parameters/screenshotFullPage" },
          {
            "schema": {
              "type": "string",
              "enum": [
                "iphone_15",
                "iphone_15_pro_max",
                "iphone_se",
                "pixel_7",
                "galaxy_s8",
                "ipad",
                "ipad_mini",
                "ipad_pro_11",
                "galaxy_tab_s4",
                "desktop_retina"
              ],
              "description": "Render as a real device: its viewport, pixel density, touch support and user agent, so the page serves its phone or tablet layout. The image keeps the device's pixel density (an `iphone_15` capture is 1179 px wide). Overrides `width` and `height`.",
              "example": "iphone_15"
            },
            "required": false,
            "description": "Render as a real device: its viewport, pixel density, touch support and user agent, so the page serves its phone or tablet layout. The image keeps the device's pixel density (an `iphone_15` capture is 1179 px wide). Overrides `width` and `height`.",
            "name": "device",
            "in": "query"
          },
          {
            "schema": {
              "type": "boolean",
              "default": false
            },
            "required": false,
            "description": "Ask the page for its dark theme (`prefers-color-scheme: dark`). Pages without one render as usual. Pass \"true\" to enable.",
            "name": "dark_mode",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Capture only the first element matching this CSS selector, e.g. `#pricing` or `header`. Answers 422 `TARGET_ELEMENT_NOT_FOUND` when nothing matches within 10 s. Not available with `format=pdf`.",
              "example": "#pricing"
            },
            "required": false,
            "description": "Capture only the first element matching this CSS selector, e.g. `#pricing` or `header`. Answers 422 `TARGET_ELEMENT_NOT_FOUND` when nothing matches within 10 s. Not available with `format=pdf`.",
            "name": "selector",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 30000,
              "default": 0
            },
            "required": false,
            "description": "Milliseconds to wait after the page loads, for content that arrives late (0–30000).",
            "name": "wait_for",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Wait (up to 10 s) for this CSS selector to be visible before capturing. Best effort: if it never appears, the page is captured as it is, with a warning.",
              "example": ".chart canvas"
            },
            "required": false,
            "description": "Wait (up to 10 s) for this CSS selector to be visible before capturing. Best effort: if it never appears, the page is captured as it is, with a warning.",
            "name": "wait_for_selector",
            "in": "query"
          },
          {
            "schema": {
              "type": "boolean",
              "default": false
            },
            "required": false,
            "description": "Block ad and tracker requests while the page loads, on top of the ad and cookie-banner hiding every screenshot gets. Pages load faster and cleaner. Pass \"true\" to enable.",
            "name": "block_ads",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 85
            },
            "required": false,
            "description": "Image quality for `jpeg` and `webp` (1–100). Default: 85.",
            "name": "quality",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Screenshot result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "data": { "$ref": "#/components/schemas/ScreenshotData" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  },
                  "required": ["success", "data", "meta"]
                },
                "example": {
                  "success": true,
                  "data": {
                    "url": "https://stripe.com",
                    "screenshot_url": "https://assets.prefetch.io/screenshots/stripe-1440x900.jpg",
                    "viewport": { "width": 1440, "height": 900 },
                    "format": "jpeg",
                    "full_page": false,
                    "captured_at": "2026-05-14T10:00:00.000Z"
                  },
                  "meta": {
                    "requestId": "c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
                    "durationMs": 2540
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid URL or parameters.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Revoked key, expired key, credit limit, or blocklisted URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "422": { "description": "URL hostname could not be resolved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "503": { "description": "Service temporarily busy — retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "504": { "description": "Request timed out.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/brand": {
      "get": {
        "operationId": "getBrand",
        "summary": "Extract brand assets",
        "description": "Extracts brand colors, logos, fonts, images, and social media links from a website. A screenshot is always captured. **Credit cost: 10.**",
        "tags": ["Endpoints"],
        "parameters": [
          { "$ref": "#/components/parameters/url" },
          {
            "name": "screenshotColors",
            "in": "query",
            "required": false,
            "description": "Extract N dominant colors from the page screenshot. Range: 2–12. Omit to skip screenshot color extraction.",
            "schema": { "type": "integer", "minimum": 2, "maximum": 12 }
          },
          {
            "name": "css",
            "in": "query",
            "required": false,
            "description": "Extract colors from linked CSS files. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "html",
            "in": "query",
            "required": false,
            "description": "Extract colors from inline HTML. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "javascript",
            "in": "query",
            "required": false,
            "description": "Extract colors from linked JS files. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "screenshotWidth",
            "in": "query",
            "required": false,
            "description": "Viewport width in pixels. Range: 320–3000. Default: 1440.",
            "schema": { "type": "integer", "minimum": 320, "maximum": 3000, "default": 1440 }
          },
          {
            "name": "screenshotHeight",
            "in": "query",
            "required": false,
            "description": "Viewport height in pixels. Range: 320–3000. Default: 900.",
            "schema": { "type": "integer", "minimum": 320, "maximum": 3000, "default": 900 }
          },
          {
            "name": "screenshotFormat",
            "in": "query",
            "required": false,
            "description": "Screenshot format. Default: `jpeg`.",
            "schema": { "type": "string", "enum": ["jpeg", "png", "pdf"], "default": "jpeg" }
          },
          {
            "name": "screenshotFullPage",
            "in": "query",
            "required": false,
            "description": "Capture the full scrollable page. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "disableAdblocker",
            "in": "query",
            "required": false,
            "description": "Disable the built-in adblocker. Pass `true` to enable (useful for sites that detect ad blockers).",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "filterAchromatic",
            "in": "query",
            "required": false,
            "description": "Exclude near-white, near-black, and greyscale colors from results. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "designTokens",
            "in": "query",
            "required": false,
            "description": "Add `brand.design_tokens`: the site's colors by role (primary, background, text, heading, link), its heading and body type, and its button and input styles, read from the rendered page. Pass `true` to enable. Requests with this set are never answered from curated data.",
            "schema": { "type": "boolean", "default": false }
          }
        ],
        "responses": {
          "200": {
            "description": "Brand extraction result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "data": { "$ref": "#/components/schemas/BrandData" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  },
                  "required": ["success", "data", "meta"]
                }
              }
            }
          },
          "400": { "description": "Invalid URL or parameters.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Revoked key, expired key, credit limit, or blocklisted URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "422": { "description": "URL hostname could not be resolved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "503": { "description": "Service temporarily busy — retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "504": { "description": "Request timed out.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/enrich": {
      "get": {
        "operationId": "enrichUrl",
        "summary": "Enrich a URL",
        "description": "Runs brand extraction, company info extraction, and website classification in parallel and returns all results in a single response. **Credit cost: 12.**\n\nThis is the most comprehensive endpoint — equivalent to calling `/brand`, `/company`, and `/classify` together but more efficient because the page is only loaded once.",
        "tags": ["Endpoints"],
        "parameters": [
          { "$ref": "#/components/parameters/url" },
          {
            "name": "screenshotColors",
            "in": "query",
            "required": false,
            "description": "Extract N dominant colors from the page screenshot. Range: 2–12.",
            "schema": { "type": "integer", "minimum": 2, "maximum": 12 }
          },
          {
            "name": "css",
            "in": "query",
            "required": false,
            "description": "Extract colors from linked CSS files. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "html",
            "in": "query",
            "required": false,
            "description": "Extract colors from inline HTML. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "javascript",
            "in": "query",
            "required": false,
            "description": "Extract colors from linked JS files. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "screenshotWidth",
            "in": "query",
            "required": false,
            "description": "Viewport width in pixels. Range: 320–3000. Default: 1440.",
            "schema": { "type": "integer", "minimum": 320, "maximum": 3000, "default": 1440 }
          },
          {
            "name": "screenshotHeight",
            "in": "query",
            "required": false,
            "description": "Viewport height in pixels. Range: 320–3000. Default: 900.",
            "schema": { "type": "integer", "minimum": 320, "maximum": 3000, "default": 900 }
          },
          {
            "name": "screenshotFormat",
            "in": "query",
            "required": false,
            "description": "Screenshot format. Default: `jpeg`.",
            "schema": { "type": "string", "enum": ["jpeg", "png", "pdf"], "default": "jpeg" }
          },
          {
            "name": "screenshotFullPage",
            "in": "query",
            "required": false,
            "description": "Capture the full scrollable page. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "disableAdblocker",
            "in": "query",
            "required": false,
            "description": "Disable the built-in adblocker. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "filterAchromatic",
            "in": "query",
            "required": false,
            "description": "Exclude near-white, near-black, and greyscale colors from results. Pass `true` to enable.",
            "schema": { "type": "boolean", "default": false }
          },
          {
            "name": "designTokens",
            "in": "query",
            "required": false,
            "description": "Add `brand.design_tokens`: the site's colors by role (primary, background, text, heading, link), its heading and body type, and its button and input styles, read from the rendered page. Pass `true` to enable. Requests with this set are never answered from curated data.",
            "schema": { "type": "boolean", "default": false }
          }
        ],
        "responses": {
          "200": {
            "description": "Enrichment result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "data": { "$ref": "#/components/schemas/EnrichData" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  },
                  "required": ["success", "data", "meta"]
                }
              }
            }
          },
          "400": { "description": "Invalid URL or parameters.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Revoked key, expired key, credit limit, or blocklisted URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "422": { "description": "URL hostname could not be resolved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "503": { "description": "Service temporarily busy — retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "504": { "description": "Request timed out.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/resolve": {
      "get": {
        "operationId": "resolveName",
        "summary": "Find a domain from a name",
        "description": "Resolves a company, brand or product name to the domain of its official website — `Stripe` → `stripe.com` — ready to pass to every other endpoint. Results are ranked, one per domain, each with a confidence; at 0.8 or above, `results[0]` is the answer. **Credit cost: 1** from the index, **3** when a live lookup runs, **0** when an index-only lookup finds nothing.",
        "tags": ["Endpoints"],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "The company, brand or product name (1–100 characters). Case, accents, punctuation and legal suffixes are ignored: \"The Coca-Cola Company\" and \"coca cola\" are the same query.",
            "schema": { "type": "string", "minLength": 1, "maxLength": 100 },
            "example": "Stripe"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of results.",
            "schema": { "type": "integer", "minimum": 1, "maximum": 10, "default": 5 }
          },
          {
            "name": "live",
            "in": "query",
            "required": false,
            "description": "When no answer reaches 0.8, look the name up live: candidate domains are verified against their own homepages. Takes a few seconds; billed 3 credits when the live lookup runs.",
            "schema": { "type": "boolean", "default": false }
          }
        ],
        "responses": {
          "200": {
            "description": "Matches, best first. Empty when nothing matched.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "enum": [true] },
                    "data": { "$ref": "#/components/schemas/ResolveData" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  },
                  "required": ["success", "data", "meta"]
                },
                "example": {
                  "success": true,
                  "data": {
                    "query": "Delta",
                    "results": [
                      { "name": "Delta Air Lines", "domain": "delta.com", "url": "https://delta.com", "confidence": 0.92, "source": "index" },
                      { "name": "DELTA", "domain": "delta.nl", "url": "https://delta.nl", "confidence": 0.79, "source": "index" }
                    ],
                    "count": 2,
                    "live_used": false,
                    "warnings": []
                  },
                  "meta": { "requestId": "b4e3d2c1-8a7b-4c3d-9e2f-1a3b5c7d9e1f", "durationMs": 41 }
                }
              }
            }
          },
          "400": { "description": "Missing, empty or over-long name.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Revoked key, expired key, or credit limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "503": { "description": "Service temporarily unavailable — retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "504": { "description": "Request timed out.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/scrape": {
      "get": {
        "operationId": "scrapeUrl",
        "summary": "Scrape a page",
        "description": "Fetches one URL and returns it in the formats you request: clean markdown, an LLM summary, cleaned or raw HTML, links, images, a screenshot, or JSON matching your own schema. Pages that need JavaScript are rendered in a real browser automatically, and a PDF URL returns the document's text as markdown. Set `max_age` to accept a stored copy of the page instead of fetching it again. **Credit cost: 1**, plus 3 when `summary` or `json` is requested.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          },
          {
            "$ref": "#/components/parameters/scrapeFormats"
          },
          {
            "$ref": "#/components/parameters/onlyMainContent"
          },
          {
            "$ref": "#/components/parameters/includeLinks"
          },
          {
            "$ref": "#/components/parameters/includeImages"
          },
          {
            "$ref": "#/components/parameters/includeBase64Images"
          },
          {
            "$ref": "#/components/parameters/includeSelectors"
          },
          {
            "$ref": "#/components/parameters/excludeSelectors"
          },
          {
            "$ref": "#/components/parameters/jsonPrompt"
          },
          {
            "$ref": "#/components/parameters/jsonSchema"
          },
          {
            "$ref": "#/components/parameters/summaryMaxWords"
          },
          {
            "$ref": "#/components/parameters/scrapeScreenshotFullPage"
          },
          {
            "$ref": "#/components/parameters/screenshotFormatParam"
          },
          {
            "$ref": "#/components/parameters/waitFor"
          },
          {
            "$ref": "#/components/parameters/waitForSelector"
          },
          {
            "$ref": "#/components/parameters/scrapeHeaders"
          },
          {
            "$ref": "#/components/parameters/mobile"
          },
          {
            "$ref": "#/components/parameters/scrapeTimeout"
          },
          {
            "$ref": "#/components/parameters/maxAge"
          },
          {
            "$ref": "#/components/parameters/storeInCache"
          },
          {
            "$ref": "#/components/parameters/checkPromptInjection"
          }
        ],
        "responses": {
          "200": {
            "description": "Page scraped.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScrapeData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "url": "https://stripe.com",
                    "final_url": "https://stripe.com",
                    "domain": "stripe.com",
                    "status_code": 200,
                    "metadata": {
                      "source_url": "https://stripe.com",
                      "final_url": "https://stripe.com",
                      "status_code": 200,
                      "title": "Stripe | Financial Infrastructure to Grow Your Revenue",
                      "description": "Stripe powers online payment processing for internet businesses.",
                      "language": "en",
                      "canonical_url": "https://stripe.com",
                      "favicon": "https://stripe.com/favicon.ico",
                      "author": null,
                      "site_name": "Stripe",
                      "published_time": null,
                      "modified_time": null,
                      "robots": null,
                      "keywords": [],
                      "open_graph": {
                        "title": "Stripe",
                        "type": "website"
                      },
                      "twitter": {
                        "card": "summary_large_image"
                      },
                      "json_ld": [],
                      "headings": [
                        {
                          "level": 1,
                          "text": "Financial infrastructure to grow your revenue"
                        }
                      ]
                    },
                    "markdown": {
                      "content": "# Financial infrastructure to grow your revenue\n\nJoin the millions of companies that use Stripe to accept payments online...",
                      "char_count": 4821,
                      "word_count": 702,
                      "truncated": false,
                      "main_content_only": true
                    },
                    "links": {
                      "internal": [
                        {
                          "url": "https://stripe.com/pricing",
                          "text": "Pricing",
                          "title": null,
                          "rel": null
                        }
                      ],
                      "external": [],
                      "count": 84
                    }
                  },
                  "meta": {
                    "requestId": "a3f2c1d4-7b6e-4f2a-9c1d-8e3f2a1b4c5d",
                    "durationMs": 2140
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/map": {
      "get": {
        "operationId": "mapSite",
        "summary": "Map a site's URLs",
        "description": "Discovers the URLs a site exposes without fetching them: its sitemaps, found through `robots.txt` and the conventional locations, merged with the links on the page itself. **Credit cost: 1.**",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          },
          {
            "$ref": "#/components/parameters/mapLimit"
          },
          {
            "$ref": "#/components/parameters/mapSearch"
          },
          {
            "$ref": "#/components/parameters/mapSitemap"
          },
          {
            "$ref": "#/components/parameters/mapIncludeSubdomains"
          },
          {
            "$ref": "#/components/parameters/mapIgnoreQueryParams"
          }
        ],
        "responses": {
          "200": {
            "description": "Links discovered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MapData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "url": "https://stripe.com",
                    "domain": "stripe.com",
                    "links": [
                      {
                        "url": "https://stripe.com/pricing",
                        "title": "Pricing",
                        "description": null,
                        "lastmod": "2026-07-02",
                        "source": "sitemap"
                      },
                      {
                        "url": "https://stripe.com/enterprise/pricing",
                        "title": null,
                        "description": null,
                        "lastmod": null,
                        "source": "sitemap"
                      }
                    ],
                    "count": 2,
                    "total_discovered": 2,
                    "sources": {
                      "sitemap": 2,
                      "links": 0
                    },
                    "sitemaps_used": [
                      "https://stripe.com/sitemap/sitemap.xml"
                    ]
                  },
                  "meta": {
                    "requestId": "b4e3d2c1-8a7b-4c3d-9e2f-1a3b5c7d9e1f",
                    "durationMs": 1830
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/crawl": {
      "post": {
        "operationId": "startCrawl",
        "summary": "Start a crawl",
        "description": "Queues a breadth-first crawl and returns its id immediately. Crawls run for minutes, so nothing waits on this request — poll `GET /crawl/{id}` for progress and results.\n\n**Credit cost: nothing to submit, 1 per page the crawl returns (4 when `scrape_options` asks for `summary`, `json` or `check_prompt_injection`).** Pages are charged as they complete, so you pay for what was fetched rather than for the `limit` you asked for.",
        "tags": [
          "Endpoints"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CrawlRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Crawl accepted and queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlJobData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_9f2c1a7b4e0d4c3a8b1e5f7d2c9a0b3e",
                    "status": "pending",
                    "url": "https://docs.stripe.com",
                    "limit": 50,
                    "max_depth": 2,
                    "created_at": "2026-08-20T09:14:03.221Z",
                    "expires_at": "2026-08-21T09:14:03.221Z"
                  },
                  "meta": {
                    "requestId": "c5f4e3d2-9b8c-4d5e-af3a-2b4c6d8e0f21",
                    "durationMs": 84
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/crawl/{id}": {
      "get": {
        "operationId": "getCrawl",
        "summary": "Get crawl status and results",
        "description": "Returns progress plus a page of crawled pages, oldest first. Follow `next` until it is null to read every page. Results stay readable for 24 hours after the crawl finishes.\n\nThis is also where crawled pages are billed: each call charges for the pages that completed since the previous call, so polling repeatedly never charges twice for the same page.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/crawlId"
          },
          {
            "$ref": "#/components/parameters/crawlSkip"
          },
          {
            "$ref": "#/components/parameters/crawlPageLimit"
          }
        ],
        "responses": {
          "200": {
            "description": "Crawl status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlStatusData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_9f2c1a7b4e0d4c3a8b1e5f7d2c9a0b3e",
                    "status": "running",
                    "url": "https://docs.stripe.com",
                    "total": 38,
                    "completed": 12,
                    "failed": 1,
                    "credits_used": 36,
                    "created_at": "2026-08-20T09:14:03.221Z",
                    "started_at": "2026-08-20T09:14:04.010Z",
                    "finished_at": null,
                    "expires_at": "2026-08-21T09:14:03.221Z",
                    "error": null,
                    "next": "/crawl/crw_9f2c1a7b4e0d4c3a8b1e5f7d2c9a0b3e?skip=25&limit=25",
                    "data": [
                      {
                        "url": "https://docs.stripe.com/payments",
                        "depth": 0,
                        "status_code": 200,
                        "ok": true,
                        "error": null,
                        "final_url": "https://docs.stripe.com/payments",
                        "domain": "docs.stripe.com",
                        "metadata": {
                          "title": "Payments",
                          "description": "Accept payments online.",
                          "language": "en"
                        },
                        "markdown": {
                          "content": "# Payments\n\nAccept payments online, in person, and around the world...",
                          "char_count": 2841,
                          "word_count": 402,
                          "truncated": false,
                          "main_content_only": true
                        }
                      }
                    ]
                  },
                  "meta": {
                    "requestId": "d6a5f4e3-ac9d-4e6f-b04b-3c5d7e9f1a32",
                    "durationMs": 96
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Crawl not found, expired, or owned by another key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "cancelCrawl",
        "summary": "Cancel a crawl",
        "description": "Stops a running crawl. Pages already crawled stay readable until the crawl expires, and are billed on the next status call as usual. Cancelling a finished crawl is a no-op that returns its final state. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/crawlId"
          }
        ],
        "responses": {
          "200": {
            "description": "Crawl cancelled, or already finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlStatusData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Crawl not found, expired, or owned by another key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/crawl/{id}/errors": {
      "get": {
        "operationId": "getCrawlErrors",
        "summary": "Get crawl errors and skipped URLs",
        "description": "Why a crawl came back with less than you expected: the pages that were fetched and failed, oldest first (paged with `skip`/`limit`), each with an `error_code`, and `skipped`, every URL the crawl found but did not fetch, counted by reason with a few examples of each. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/crawlId"
          },
          {
            "$ref": "#/components/parameters/crawlSkip"
          },
          {
            "$ref": "#/components/parameters/crawlPageLimit"
          }
        ],
        "responses": {
          "200": {
            "description": "Failed pages and skip reasons.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlErrorsData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_9f2c1a7b4e0d4c3a8b1e5f7d2c9a0b3e",
                    "status": "completed",
                    "failed": [
                      {
                        "url": "https://docs.stripe.com/legacy/v1",
                        "depth": 2,
                        "status_code": null,
                        "error": "Failed to load page (HTTP 503)",
                        "error_code": "TARGET_SERVER_ERROR"
                      }
                    ],
                    "failed_total": 1,
                    "skipped": {
                      "out-of-scope": {
                        "count": 41,
                        "samples": [
                          "https://docs.stripe.com/blog/2024",
                          "https://docs.stripe.com/jobs"
                        ]
                      },
                      "robots": {
                        "count": 3,
                        "samples": [
                          "https://docs.stripe.com/search"
                        ]
                      }
                    },
                    "next": null
                  },
                  "meta": {
                    "requestId": "4c1e2a9b-7d3f-4b8e-9a6c-1f2e3d4c5b6a",
                    "durationMs": 41
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Crawl not found, expired, or owned by another key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/batch/scrape": {
      "post": {
        "operationId": "startBatchScrape",
        "summary": "Scrape a list of URLs",
        "description": "Queues a list of pages as one job and returns its id immediately. Each page is fetched and rendered exactly as `GET /scrape` would, configured through `scrape_options`; nothing is followed, and no sitemap or robots.txt is read. Poll `GET /batch/scrape/{id}` for progress and results, or pass a `webhook`.\n\n**Credit cost: nothing to submit, 1 per page returned (4 when `scrape_options` asks for `summary`, `json` or `check_prompt_injection`).** Pages are charged as they complete.",
        "tags": [
          "Endpoints"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchScrapeRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/BatchJobData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_5a8d2e7f1c4b4a9e8d3c6b1a0f9e8d7c",
                    "status": "pending",
                    "url_count": 2,
                    "invalid_urls": [],
                    "created_at": "2026-10-11T09:14:03.221Z",
                    "expires_at": "2026-10-12T09:14:03.221Z"
                  },
                  "meta": {
                    "requestId": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                    "durationMs": 58
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/batch/scrape/{id}": {
      "get": {
        "operationId": "getBatchScrape",
        "summary": "Get batch status and results",
        "description": "Progress plus a page of scraped pages, in completion order: the same response as `GET /crawl/{id}`, with `kind: \"batch\"`. Follow `next` until it is null. Pages are billed here as they complete, never twice.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/crawlId"
          },
          {
            "$ref": "#/components/parameters/crawlSkip"
          },
          {
            "$ref": "#/components/parameters/crawlPageLimit"
          }
        ],
        "responses": {
          "200": {
            "description": "Batch status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlStatusData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Crawl not found, expired, or owned by another key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "cancelBatchScrape",
        "summary": "Cancel a batch",
        "description": "Stops a running batch. Pages already scraped stay readable until it expires, and are billed on the next status call as usual. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/crawlId"
          }
        ],
        "responses": {
          "200": {
            "description": "Batch cancelled, or already finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlStatusData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Crawl not found, expired, or owned by another key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/batch/scrape/{id}/errors": {
      "get": {
        "operationId": "getBatchScrapeErrors",
        "summary": "Get batch errors",
        "description": "The pages of a batch that failed, oldest first, each with an `error_code`, and `skipped`: URLs left out, by reason (`duplicate`, `blocklist`, `invalid`). Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/crawlId"
          },
          {
            "$ref": "#/components/parameters/crawlSkip"
          },
          {
            "$ref": "#/components/parameters/crawlPageLimit"
          }
        ],
        "responses": {
          "200": {
            "description": "Failed pages and skip reasons.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlErrorsData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, or blocklisted URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The URL hostname could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Crawl not found, expired, or owned by another key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/monitor": {
      "post": {
        "operationId": "createMonitor",
        "summary": "Create a monitor",
        "description": "Watches pages on a schedule and tells you what changed. Each check re-fetches every target — a fixed list of URLs (`scrape`) or a whole site (`crawl`) — and compares each page with the previous check: `same`, `new`, `changed`, `removed` or `error`, with a diff. Give it a `goal` and every change is judged against it, so only meaningful changes reach your webhook or inbox.\n\nThe first check records a baseline: every page is `new`, and no `monitor.page` events or emails are sent for it.\n\nWith `email`, each check that finds changes sends one email listing them. An address on your Prefetch account receives alerts at once; any other address confirms from an email first.\n\n**Credit cost: none to create.** Each check bills 1 credit per page it fetches (the `/scrape` rate, 4 on targets tracking `json`), plus 1 per changed page judged against the goal.",
        "tags": [
          "Endpoints"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Monitor created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                    "name": "Competitor pricing",
                    "status": "active",
                    "schedule": {
                      "cron": "0 9 * * 1-5",
                      "timezone": "Europe/Athens",
                      "text": "every weekday at 9am"
                    },
                    "next_run_at": "2026-10-12T06:00:00.000Z",
                    "last_run_at": null,
                    "current_check_id": null,
                    "goal": "Alert me when a plan price or its included features change",
                    "judge_enabled": true,
                    "targets": [
                      {
                        "id": "tgt_8d1e0f2a3b4c5d6e",
                        "type": "scrape",
                        "urls": [
                          "https://example.com/pricing"
                        ],
                        "scrape_options": {
                          "only_main_content": true,
                          "include_links": true,
                          "include_images": false,
                          "include_selectors": [],
                          "exclude_selectors": []
                        },
                        "change_tracking": {
                          "modes": [
                            "json"
                          ],
                          "json_prompt": "Each plan: name, monthly price, headline features"
                        }
                      },
                      {
                        "id": "tgt_1a2b3c4d5e6f7a8b",
                        "type": "crawl",
                        "url": "https://example.com/changelog",
                        "crawl_options": {
                          "limit": 25,
                          "max_depth": 2,
                          "include_paths": [
                            "^/changelog/"
                          ],
                          "exclude_paths": [],
                          "allow_subdomains": false,
                          "ignore_query_params": true,
                          "respect_robots_txt": true,
                          "use_sitemap": true,
                          "delay_ms": 0,
                          "concurrency": 2
                        },
                        "scrape_options": {
                          "only_main_content": true,
                          "include_links": true,
                          "include_images": false,
                          "include_selectors": [],
                          "exclude_selectors": []
                        },
                        "change_tracking": {
                          "modes": [
                            "markdown"
                          ]
                        }
                      }
                    ],
                    "webhook": {
                      "url": "https://you.example.org/hooks/prefetch",
                      "headers": {},
                      "metadata": {
                        "env": "production"
                      },
                      "events": [
                        "monitor.page",
                        "monitor.check.completed"
                      ],
                      "secret": "whsec_4f1c9e2a7b3d8e6f0a5c1b9d2e7f3a8c4b6d0e1f9a2c5b7d"
                    },
                    "email": {
                      "to": [
                        "you@example.com"
                      ],
                      "recipients": [
                        {
                          "address": "you@example.com",
                          "status": "active",
                          "confirmation_sent_at": null,
                          "confirmed_at": "2026-10-09T10:00:00.000Z",
                          "unsubscribed_at": null
                        }
                      ]
                    },
                    "retention_days": 30,
                    "estimated_credits_per_check": 55,
                    "estimated_credits_per_month": 1155,
                    "last_check_summary": null,
                    "created_at": "2026-10-09T10:00:00.000Z",
                    "updated_at": "2026-10-09T10:00:00.000Z"
                  },
                  "meta": {
                    "requestId": "b8f1d2e3-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
                    "durationMs": 61
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listMonitors",
        "summary": "List monitors",
        "description": "The monitors your API key owns, newest first. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorListLimit"
          },
          {
            "$ref": "#/components/parameters/monitorListOffset"
          }
        ],
        "responses": {
          "200": {
            "description": "Monitors.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorListData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "monitors": [
                      {
                        "id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                        "name": "Competitor pricing",
                        "status": "active",
                        "schedule": {
                          "cron": "0 9 * * 1-5",
                          "timezone": "Europe/Athens",
                          "text": "every weekday at 9am"
                        },
                        "next_run_at": "2026-10-13T06:00:00.000Z",
                        "last_run_at": "2026-10-12T06:00:04.112Z",
                        "current_check_id": null,
                        "goal": "Alert me when a plan price or its included features change",
                        "judge_enabled": true,
                        "targets": [
                          {
                            "id": "tgt_8d1e0f2a3b4c5d6e",
                            "type": "scrape",
                            "urls": [
                              "https://example.com/pricing"
                            ],
                            "scrape_options": {
                              "only_main_content": true,
                              "include_links": true,
                              "include_images": false,
                              "include_selectors": [],
                              "exclude_selectors": []
                            },
                            "change_tracking": {
                              "modes": [
                                "json"
                              ],
                              "json_prompt": "Each plan: name, monthly price, headline features"
                            }
                          },
                          {
                            "id": "tgt_1a2b3c4d5e6f7a8b",
                            "type": "crawl",
                            "url": "https://example.com/changelog",
                            "crawl_options": {
                              "limit": 25,
                              "max_depth": 2,
                              "include_paths": [
                                "^/changelog/"
                              ],
                              "exclude_paths": [],
                              "allow_subdomains": false,
                              "ignore_query_params": true,
                              "respect_robots_txt": true,
                              "use_sitemap": true,
                              "delay_ms": 0,
                              "concurrency": 2
                            },
                            "scrape_options": {
                              "only_main_content": true,
                              "include_links": true,
                              "include_images": false,
                              "include_selectors": [],
                              "exclude_selectors": []
                            },
                            "change_tracking": {
                              "modes": [
                                "markdown"
                              ]
                            }
                          }
                        ],
                        "webhook": {
                          "url": "https://you.example.org/hooks/prefetch",
                          "headers": {},
                          "metadata": {
                            "env": "production"
                          },
                          "events": [
                            "monitor.page",
                            "monitor.check.completed"
                          ],
                          "secret": "whsec_4f1c9e2a7b3d8e6f0a5c1b9d2e7f3a8c4b6d0e1f9a2c5b7d"
                        },
                        "email": {
                          "to": [
                            "you@example.com"
                          ],
                          "recipients": [
                            {
                              "address": "you@example.com",
                              "status": "active",
                              "confirmation_sent_at": null,
                              "confirmed_at": "2026-10-09T10:00:00.000Z",
                              "unsubscribed_at": null
                            }
                          ]
                        },
                        "retention_days": 30,
                        "estimated_credits_per_check": 55,
                        "estimated_credits_per_month": 1155,
                        "last_check_summary": {
                          "check_id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                          "status": "completed",
                          "finished_at": "2026-10-12T06:01:27.930Z",
                          "total_pages": 19,
                          "same": 16,
                          "new": 1,
                          "changed": 1,
                          "removed": 1,
                          "error": 0
                        },
                        "created_at": "2026-10-09T10:00:00.000Z",
                        "updated_at": "2026-10-09T10:00:00.000Z"
                      }
                    ],
                    "total": 1,
                    "next": null
                  },
                  "meta": {
                    "requestId": "c9a2e3f4-5b6c-4d7e-9f80-1a2b3c4d5e6f",
                    "durationMs": 47
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/monitor/{id}": {
      "get": {
        "operationId": "getMonitor",
        "summary": "Get a monitor",
        "description": "The monitor's settings, next run, credit estimate and the summary of its last check. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorId"
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                    "name": "Competitor pricing",
                    "status": "active",
                    "schedule": {
                      "cron": "0 9 * * 1-5",
                      "timezone": "Europe/Athens",
                      "text": "every weekday at 9am"
                    },
                    "next_run_at": "2026-10-13T06:00:00.000Z",
                    "last_run_at": "2026-10-12T06:00:04.112Z",
                    "current_check_id": null,
                    "goal": "Alert me when a plan price or its included features change",
                    "judge_enabled": true,
                    "targets": [
                      {
                        "id": "tgt_8d1e0f2a3b4c5d6e",
                        "type": "scrape",
                        "urls": [
                          "https://example.com/pricing"
                        ],
                        "scrape_options": {
                          "only_main_content": true,
                          "include_links": true,
                          "include_images": false,
                          "include_selectors": [],
                          "exclude_selectors": []
                        },
                        "change_tracking": {
                          "modes": [
                            "json"
                          ],
                          "json_prompt": "Each plan: name, monthly price, headline features"
                        }
                      },
                      {
                        "id": "tgt_1a2b3c4d5e6f7a8b",
                        "type": "crawl",
                        "url": "https://example.com/changelog",
                        "crawl_options": {
                          "limit": 25,
                          "max_depth": 2,
                          "include_paths": [
                            "^/changelog/"
                          ],
                          "exclude_paths": [],
                          "allow_subdomains": false,
                          "ignore_query_params": true,
                          "respect_robots_txt": true,
                          "use_sitemap": true,
                          "delay_ms": 0,
                          "concurrency": 2
                        },
                        "scrape_options": {
                          "only_main_content": true,
                          "include_links": true,
                          "include_images": false,
                          "include_selectors": [],
                          "exclude_selectors": []
                        },
                        "change_tracking": {
                          "modes": [
                            "markdown"
                          ]
                        }
                      }
                    ],
                    "webhook": {
                      "url": "https://you.example.org/hooks/prefetch",
                      "headers": {},
                      "metadata": {
                        "env": "production"
                      },
                      "events": [
                        "monitor.page",
                        "monitor.check.completed"
                      ],
                      "secret": "whsec_4f1c9e2a7b3d8e6f0a5c1b9d2e7f3a8c4b6d0e1f9a2c5b7d"
                    },
                    "email": {
                      "to": [
                        "you@example.com"
                      ],
                      "recipients": [
                        {
                          "address": "you@example.com",
                          "status": "active",
                          "confirmation_sent_at": null,
                          "confirmed_at": "2026-10-09T10:00:00.000Z",
                          "unsubscribed_at": null
                        }
                      ]
                    },
                    "retention_days": 30,
                    "estimated_credits_per_check": 55,
                    "estimated_credits_per_month": 1155,
                    "last_check_summary": {
                      "check_id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                      "status": "completed",
                      "finished_at": "2026-10-12T06:01:27.930Z",
                      "total_pages": 19,
                      "same": 16,
                      "new": 1,
                      "changed": 1,
                      "removed": 1,
                      "error": 0
                    },
                    "created_at": "2026-10-09T10:00:00.000Z",
                    "updated_at": "2026-10-09T10:00:00.000Z"
                  },
                  "meta": {
                    "requestId": "d0b3f4a5-6c7d-4e8f-a091-2b3c4d5e6f70",
                    "durationMs": 39
                  }
                }
              }
            }
          },
          "404": {
            "description": "Monitor not found — or not yours. Monitor ids are unguessable, so another key's monitor is reported as not found rather than forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateMonitor",
        "summary": "Update a monitor",
        "description": "Changes any subset of the monitor's fields. `status: \"paused\"` stops its schedule and `\"active\"` resumes it. Replacing `targets` keeps the snapshots of targets that still watch the same URLs. `email.to` replaces the list of addresses; addresses you keep keep their status. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Monitor updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                    "name": "Competitor pricing",
                    "status": "paused",
                    "schedule": {
                      "cron": "0 9 * * 1-5",
                      "timezone": "Europe/Athens",
                      "text": "every weekday at 9am"
                    },
                    "next_run_at": null,
                    "last_run_at": "2026-10-12T06:00:04.112Z",
                    "current_check_id": null,
                    "goal": "Alert me when a plan price or its included features change",
                    "judge_enabled": true,
                    "targets": [
                      {
                        "id": "tgt_8d1e0f2a3b4c5d6e",
                        "type": "scrape",
                        "urls": [
                          "https://example.com/pricing"
                        ],
                        "scrape_options": {
                          "only_main_content": true,
                          "include_links": true,
                          "include_images": false,
                          "include_selectors": [],
                          "exclude_selectors": []
                        },
                        "change_tracking": {
                          "modes": [
                            "json"
                          ],
                          "json_prompt": "Each plan: name, monthly price, headline features"
                        }
                      },
                      {
                        "id": "tgt_1a2b3c4d5e6f7a8b",
                        "type": "crawl",
                        "url": "https://example.com/changelog",
                        "crawl_options": {
                          "limit": 25,
                          "max_depth": 2,
                          "include_paths": [
                            "^/changelog/"
                          ],
                          "exclude_paths": [],
                          "allow_subdomains": false,
                          "ignore_query_params": true,
                          "respect_robots_txt": true,
                          "use_sitemap": true,
                          "delay_ms": 0,
                          "concurrency": 2
                        },
                        "scrape_options": {
                          "only_main_content": true,
                          "include_links": true,
                          "include_images": false,
                          "include_selectors": [],
                          "exclude_selectors": []
                        },
                        "change_tracking": {
                          "modes": [
                            "markdown"
                          ]
                        }
                      }
                    ],
                    "webhook": {
                      "url": "https://you.example.org/hooks/prefetch",
                      "headers": {},
                      "metadata": {
                        "env": "production"
                      },
                      "events": [
                        "monitor.page",
                        "monitor.check.completed"
                      ],
                      "secret": "whsec_4f1c9e2a7b3d8e6f0a5c1b9d2e7f3a8c4b6d0e1f9a2c5b7d"
                    },
                    "email": {
                      "to": [
                        "you@example.com"
                      ],
                      "recipients": [
                        {
                          "address": "you@example.com",
                          "status": "active",
                          "confirmation_sent_at": null,
                          "confirmed_at": "2026-10-09T10:00:00.000Z",
                          "unsubscribed_at": null
                        }
                      ]
                    },
                    "retention_days": 30,
                    "estimated_credits_per_check": 55,
                    "estimated_credits_per_month": 1155,
                    "last_check_summary": {
                      "check_id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                      "status": "completed",
                      "finished_at": "2026-10-12T06:01:27.930Z",
                      "total_pages": 19,
                      "same": 16,
                      "new": 1,
                      "changed": 1,
                      "removed": 1,
                      "error": 0
                    },
                    "created_at": "2026-10-09T10:00:00.000Z",
                    "updated_at": "2026-10-12T08:30:00.000Z"
                  },
                  "meta": {
                    "requestId": "e1c4a5b6-7d8e-4f90-b1a2-3c4d5e6f7081",
                    "durationMs": 52
                  }
                }
              }
            }
          },
          "404": {
            "description": "Monitor not found — or not yours. Monitor ids are unguessable, so another key's monitor is reported as not found rather than forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteMonitor",
        "summary": "Delete a monitor",
        "description": "Deletes the monitor with its checks, snapshots and pending webhooks, and stops all future charges. To stop it for a while, pause it instead. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorId"
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorDeleteData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                    "deleted": true
                  },
                  "meta": {
                    "requestId": "f2d5b6c7-8e9f-4a01-82b3-4d5e6f708192",
                    "durationMs": 33
                  }
                }
              }
            }
          },
          "404": {
            "description": "Monitor not found — or not yours. Monitor ids are unguessable, so another key's monitor is reported as not found rather than forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/monitor/{id}/run": {
      "post": {
        "operationId": "runMonitor",
        "summary": "Run a check now",
        "description": "Queues a check outside the schedule and returns it immediately. Poll `GET /monitor/{id}/checks/{checkId}` for the result. Works on paused monitors too.\n\n**Credit cost: the same as a scheduled check** — 1 per page fetched (4 in `json` mode), plus 1 per changed page judged.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorId"
          }
        ],
        "responses": {
          "202": {
            "description": "Check queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorCheckData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                    "monitor_id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                    "status": "queued",
                    "trigger": "manual",
                    "scheduled_for": null,
                    "started_at": null,
                    "finished_at": null,
                    "estimated_credits": 55,
                    "actual_credits": 0,
                    "summary": {
                      "total_pages": 0,
                      "same": 0,
                      "new": 0,
                      "changed": 0,
                      "removed": 0,
                      "error": 0
                    },
                    "target_results": null,
                    "error": null,
                    "created_at": "2026-10-09T10:05:00.000Z",
                    "updated_at": "2026-10-09T10:05:00.000Z"
                  },
                  "meta": {
                    "requestId": "a3e6c7d8-9f0a-4b12-93c4-5e6f708192a3",
                    "durationMs": 38
                  }
                }
              }
            }
          },
          "404": {
            "description": "Monitor not found — or not yours. Monitor ids are unguessable, so another key's monitor is reported as not found rather than forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "A check is already queued or running for this monitor. The message names it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/monitor/{id}/checks": {
      "get": {
        "operationId": "listMonitorChecks",
        "summary": "List checks",
        "description": "The monitor's checks, newest first, for as long as its `retention_days` keeps them. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorId"
          },
          {
            "$ref": "#/components/parameters/monitorListLimit"
          },
          {
            "$ref": "#/components/parameters/monitorListOffset"
          },
          {
            "$ref": "#/components/parameters/monitorCheckStatus"
          }
        ],
        "responses": {
          "200": {
            "description": "Checks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorCheckListData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "checks": [
                      {
                        "id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                        "monitor_id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                        "status": "completed",
                        "trigger": "scheduled",
                        "scheduled_for": "2026-10-12T06:00:00.000Z",
                        "started_at": "2026-10-12T06:00:04.112Z",
                        "finished_at": "2026-10-12T06:01:27.930Z",
                        "estimated_credits": 55,
                        "actual_credits": 24,
                        "summary": {
                          "total_pages": 19,
                          "same": 16,
                          "new": 1,
                          "changed": 1,
                          "removed": 1,
                          "error": 0
                        },
                        "target_results": [
                          {
                            "target_id": "tgt_8d1e0f2a3b4c5d6e",
                            "type": "scrape",
                            "pages": 1,
                            "checked": 1,
                            "baseline": false
                          },
                          {
                            "target_id": "tgt_1a2b3c4d5e6f7a8b",
                            "type": "crawl",
                            "discovered": 17,
                            "limit": 25,
                            "complete": true,
                            "baseline": false
                          }
                        ],
                        "error": null,
                        "created_at": "2026-10-12T06:00:00.513Z",
                        "updated_at": "2026-10-12T06:01:27.930Z"
                      }
                    ],
                    "total": 1,
                    "next": null
                  },
                  "meta": {
                    "requestId": "b4f7d8e9-0a1b-4c23-a4d5-6f708192a3b4",
                    "durationMs": 44
                  }
                }
              }
            }
          },
          "404": {
            "description": "Monitor not found — or not yours. Monitor ids are unguessable, so another key's monitor is reported as not found rather than forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/monitor/{id}/checks/{checkId}": {
      "get": {
        "operationId": "getMonitorCheck",
        "summary": "Get a check",
        "description": "One check with a page of its per-page results: status, diff, the judge's verdict and, in JSON mode, the current extraction. Filter with `status=changed` to see only what changed, and follow `next` until it is null. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/monitorId"
          },
          {
            "$ref": "#/components/parameters/monitorCheckId"
          },
          {
            "$ref": "#/components/parameters/monitorPageSkip"
          },
          {
            "$ref": "#/components/parameters/monitorPageLimit"
          },
          {
            "$ref": "#/components/parameters/monitorPageStatus"
          }
        ],
        "responses": {
          "200": {
            "description": "Check with page results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MonitorCheckDetailData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                    "monitor_id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                    "status": "completed",
                    "trigger": "scheduled",
                    "scheduled_for": "2026-10-12T06:00:00.000Z",
                    "started_at": "2026-10-12T06:00:04.112Z",
                    "finished_at": "2026-10-12T06:01:27.930Z",
                    "estimated_credits": 55,
                    "actual_credits": 24,
                    "summary": {
                      "total_pages": 19,
                      "same": 16,
                      "new": 1,
                      "changed": 1,
                      "removed": 1,
                      "error": 0
                    },
                    "target_results": [
                      {
                        "target_id": "tgt_8d1e0f2a3b4c5d6e",
                        "type": "scrape",
                        "pages": 1,
                        "checked": 1,
                        "baseline": false
                      },
                      {
                        "target_id": "tgt_1a2b3c4d5e6f7a8b",
                        "type": "crawl",
                        "discovered": 17,
                        "limit": 25,
                        "complete": true,
                        "baseline": false
                      }
                    ],
                    "error": null,
                    "created_at": "2026-10-12T06:00:00.513Z",
                    "updated_at": "2026-10-12T06:01:27.930Z",
                    "notifications": {
                      "webhook": {
                        "pending": 0,
                        "delivered": 2,
                        "failed": 0
                      },
                      "email": {
                        "pending": 0,
                        "sent": 1,
                        "failed": 0
                      }
                    },
                    "pages": [
                      {
                        "target_id": "tgt_8d1e0f2a3b4c5d6e",
                        "url": "https://example.com/pricing",
                        "status": "changed",
                        "status_code": 200,
                        "error": null,
                        "title": "Pricing — Example",
                        "previous_check_id": "chk_51b0c2d3e4f5a6b7c8d9e0f1a2b3c4d5",
                        "is_meaningful": true,
                        "judgment": {
                          "meaningful": true,
                          "confidence": "high",
                          "reason": "The Starter plan's price went from $19 to $24 a month.",
                          "meaningful_changes": [
                            {
                              "type": "changed",
                              "before": "$19/mo",
                              "after": "$24/mo",
                              "reason": "A plan price changed."
                            }
                          ]
                        },
                        "diff": {
                          "fields": {
                            "plans[0].price": {
                              "previous": "$19/mo",
                              "current": "$24/mo",
                              "change": "changed"
                            }
                          },
                          "changed_fields": 1
                        },
                        "snapshot": {
                          "json": {
                            "plans": [
                              {
                                "name": "Starter",
                                "price": "$24/mo",
                                "features": [
                                  "3 seats",
                                  "Email support"
                                ]
                              },
                              {
                                "name": "Pro",
                                "price": "$49/mo",
                                "features": [
                                  "Unlimited seats",
                                  "SSO"
                                ]
                              }
                            ]
                          }
                        }
                      },
                      {
                        "target_id": "tgt_1a2b3c4d5e6f7a8b",
                        "url": "https://example.com/changelog/2026-10-11",
                        "status": "new",
                        "status_code": 200,
                        "error": null,
                        "title": "October 11 release",
                        "previous_check_id": null,
                        "is_meaningful": false,
                        "judgment": {
                          "meaningful": false,
                          "confidence": "high",
                          "reason": "A bug-fix release; no plan or price changes.",
                          "meaningful_changes": []
                        },
                        "diff": {
                          "text": "--- previous\n+++ current\n@@ -1,0 +1,4 @@\n+# October 11 release\n+\n+- Fixed CSV export of invoices\n+- Faster dashboard loading\n",
                          "added_lines": 4,
                          "removed_lines": 0,
                          "truncated": false,
                          "hunks": [
                            {
                              "old_start": 1,
                              "old_lines": 0,
                              "new_start": 1,
                              "new_lines": 4,
                              "lines": [
                                {
                                  "type": "added",
                                  "content": "# October 11 release"
                                },
                                {
                                  "type": "added",
                                  "content": ""
                                },
                                {
                                  "type": "added",
                                  "content": "- Fixed CSV export of invoices"
                                },
                                {
                                  "type": "added",
                                  "content": "- Faster dashboard loading"
                                }
                              ]
                            }
                          ]
                        },
                        "snapshot": null
                      }
                    ],
                    "next": "/monitor/mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c/checks/chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a?skip=2&limit=2"
                  },
                  "meta": {
                    "requestId": "c5a8e9f0-1b2c-4d34-b5e6-708192a3b4c5",
                    "durationMs": 74
                  }
                }
              }
            }
          },
          "404": {
            "description": "Monitor or check not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters. The message names the field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, credit limit, blocklisted URL, monitor limit reached, or a RapidAPI subscription — monitors need a direct Prefetch API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Monitoring is temporarily unavailable. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/search": {
      "get": {
        "operationId": "searchWeb",
        "summary": "Search the web",
        "description": "Searches the web (Google results) and returns each result's title, URL and snippet, best first. `type=news` returns recent articles with their publisher and date. Narrow it with `time_range`, `country`, `language`, `location`, `include_domains` and `exclude_domains`.\n\nAsk for page content and each result page is scraped in the same request — through `formats` on GET, or a `scrape_options` object on POST, taking the options /scrape takes — and returned in `scrape` on its result. A page that cannot be fetched in time gets a `scrape_error` instead and is not charged.\n\n**Credit cost: 2 per 10 results** (rounded up), plus 1 per result page scraped (4 for `summary` or `json`). Failed requests are never charged.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "What to search for, as you would type it into Google (1–400 characters). Search operators work (`\"exact phrase\"`, `-word`, `filetype:pdf`). `q` is accepted too.",
              "example": "best open source CRM"
            },
            "required": true,
            "description": "What to search for, as you would type it into Google (1–400 characters). Search operators work (`\"exact phrase\"`, `-word`, `filetype:pdf`). `q` is accepted too.",
            "name": "query",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Results to return (1–50; 1–10 when results are scraped). Default: 10.",
              "example": "10"
            },
            "required": false,
            "description": "Results to return (1–50; 1–10 when results are scraped). Default: 10.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "web",
                "news"
              ],
              "description": "`web` (default) or `news` — recent articles with their publisher and date."
            },
            "required": false,
            "description": "`web` (default) or `news` — recent articles with their publisher and date.",
            "name": "type",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Two-letter country code to search from, e.g. `us`, `de`.",
              "example": "us"
            },
            "required": false,
            "description": "Two-letter country code to search from, e.g. `us`, `de`.",
            "name": "country",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Two-letter language code for the results, e.g. `en`, `de`.",
              "example": "en"
            },
            "required": false,
            "description": "Two-letter language code for the results, e.g. `en`, `de`.",
            "name": "language",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "A city or region to search from, e.g. `Berlin, Germany`."
            },
            "required": false,
            "description": "A city or region to search from, e.g. `Berlin, Germany`.",
            "name": "location",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "hour",
                "day",
                "week",
                "month",
                "year"
              ],
              "description": "Only results from the past hour, day, week, month or year."
            },
            "required": false,
            "description": "Only results from the past hour, day, week, month or year.",
            "name": "time_range",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Comma-separated domains to search within (up to 10).",
              "example": "github.com,gitlab.com"
            },
            "required": false,
            "description": "Comma-separated domains to search within (up to 10).",
            "name": "include_domains",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Comma-separated domains to leave out (up to 10).",
              "example": "pinterest.com"
            },
            "required": false,
            "description": "Comma-separated domains to leave out (up to 10).",
            "name": "exclude_domains",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Scrape each result page into these formats (the /scrape formats: markdown, summary, html, raw_html, links, images, json, screenshot). Omit to return search results only.",
              "example": "markdown"
            },
            "required": false,
            "description": "Scrape each result page into these formats (the /scrape formats: markdown, summary, html, raw_html, links, images, json, screenshot). Omit to return search results only.",
            "name": "formats",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "With `formats`: strip navigation, sidebars and footers from each page. Default: true."
            },
            "required": false,
            "description": "With `formats`: strip navigation, sidebars and footers from each page. Default: true.",
            "name": "only_main_content",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "With `formats`: accept a stored copy of a page fetched at most this many milliseconds ago.",
              "example": "86400000"
            },
            "required": false,
            "description": "With `formats`: accept a stored copy of a page fetched at most this many milliseconds ago.",
            "name": "max_age",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Give up after this many milliseconds (5,000–45000). Result pages still loading are returned with a `scrape_error` and not charged.",
              "example": "30000"
            },
            "required": false,
            "description": "Give up after this many milliseconds (5,000–45000). Result pages still loading are returned with a `scrape_error` and not charged.",
            "name": "timeout",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Results, best first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/SearchData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "query": "stripe pricing",
                    "type": "web",
                    "count": 2,
                    "scraped": 0,
                    "warnings": [],
                    "results": [
                      {
                        "position": 1,
                        "url": "https://stripe.com/pricing",
                        "title": "Pricing & Fees | Stripe",
                        "description": "Find Stripe fees and pricing information…",
                        "date": null,
                        "source": null,
                        "image_url": null
                      },
                      {
                        "position": 2,
                        "url": "https://docs.stripe.com/billing/subscriptions/pricing",
                        "title": "Pricing models | Stripe Documentation",
                        "description": "Learn about common pricing models…",
                        "date": null,
                        "source": null,
                        "image_url": null
                      }
                    ]
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "searchWebPost",
        "summary": "Search the web (JSON body)",
        "description": "Searches the web (Google results) and returns each result's title, URL and snippet, best first. `type=news` returns recent articles with their publisher and date. Narrow it with `time_range`, `country`, `language`, `location`, `include_domains` and `exclude_domains`.\n\nAsk for page content and each result page is scraped in the same request — through `formats` on GET, or a `scrape_options` object on POST, taking the options /scrape takes — and returned in `scrape` on its result. A page that cannot be fetched in time gets a `scrape_error` instead and is not charged.\n\n**Credit cost: 2 per 10 results** (rounded up), plus 1 per result page scraped (4 for `summary` or `json`). Failed requests are never charged.\n\nThe same endpoint as `GET /search`, with its options as typed JSON — the way to send `scrape_options`.",
        "tags": [
          "Endpoints"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Results, best first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/SearchData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "query": "stripe pricing",
                    "type": "web",
                    "count": 2,
                    "scraped": 0,
                    "warnings": [],
                    "results": [
                      {
                        "position": 1,
                        "url": "https://stripe.com/pricing",
                        "title": "Pricing & Fees | Stripe",
                        "description": "Find Stripe fees and pricing information…",
                        "date": null,
                        "source": null,
                        "image_url": null
                      },
                      {
                        "position": 2,
                        "url": "https://docs.stripe.com/billing/subscriptions/pricing",
                        "title": "Pricing models | Stripe Documentation",
                        "description": "Learn about common pricing models…",
                        "date": null,
                        "source": null,
                        "image_url": null
                      }
                    ]
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/styleguide": {
      "get": {
        "operationId": "getStyleguide",
        "summary": "Extract a design system",
        "description": "Reads the design system off the rendered page: colors by role (primary, secondary, accent, background, surface, text, heading, link, border) and the full palette; heading, body and monospace fonts with the type scale (h1–h6, body, small, label, nav — size, weight, line height, letter spacing); the spacing rhythm and its base unit; corner radii and shadows by size; border style; the primary and secondary button, input, card and link styles; the media-query breakpoints; and the site's own CSS custom properties. `exports` has the same as CSS variables and a Tailwind theme, ready to paste. Built for coding agents that need to match a site's look.\n\nBest effort: a value the page gives no reliable answer for is null. Never answered from curated data. **Credit cost: 10.**",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "description": "Target website URL. https:// is prepended automatically if the protocol is omitted.",
              "example": "https://stripe.com"
            },
            "required": true,
            "description": "Target website URL. https:// is prepended automatically if the protocol is omitted.",
            "name": "url",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Read the site's dark theme (`prefers-color-scheme: dark`) instead of its default one. Sites without one return their usual theme, with `color_scheme` saying which it is. Pass \"true\" to enable."
            },
            "required": false,
            "description": "Read the site's dark theme (`prefers-color-scheme: dark`) instead of its default one. Sites without one return their usual theme, with `color_scheme` saying which it is. Pass \"true\" to enable.",
            "name": "dark_mode",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The site's design system.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/StyleguideData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "url": "https://stripe.com",
                    "domain": "stripe.com",
                    "dark_mode": false,
                    "styleguide": {
                      "color_scheme": "light",
                      "colors": {
                        "primary": "#533AFD",
                        "secondary": null,
                        "accent": null,
                        "background": "#FFFFFF",
                        "surface": "#E5EDF5",
                        "text": "#50617A",
                        "text_muted": "#64748D",
                        "heading": "#061B31",
                        "link": "#533AFD",
                        "border": "#E5EDF5"
                      },
                      "palette": [
                        {
                          "hex": "#533AFD",
                          "role": "primary"
                        },
                        {
                          "hex": "#FFFFFF",
                          "role": "background"
                        },
                        {
                          "hex": "#061B31",
                          "role": "heading"
                        }
                      ],
                      "typography": {
                        "font_families": {
                          "heading": {
                            "family": "sohne-var",
                            "stack": [
                              "sohne-var",
                              "SF Pro Display",
                              "sans-serif"
                            ]
                          },
                          "body": {
                            "family": "sohne-var",
                            "stack": [
                              "sohne-var",
                              "SF Pro Display",
                              "sans-serif"
                            ]
                          },
                          "mono": null
                        },
                        "styles": {
                          "h1": {
                            "font_family": "sohne-var",
                            "font_size": "48px",
                            "font_weight": 300,
                            "line_height": "55.2px",
                            "letter_spacing": "-0.96px",
                            "text_transform": null
                          },
                          "body": {
                            "font_family": "sohne-var",
                            "font_size": "16px",
                            "font_weight": 300,
                            "line_height": "22.4px",
                            "letter_spacing": null,
                            "text_transform": null
                          }
                        },
                        "base_font_size": "16px",
                        "scale": {
                          "ratio": 1.441,
                          "name": "augmented fourth"
                        },
                        "web_fonts": {
                          "google_fonts": [],
                          "adobe_fonts": []
                        }
                      },
                      "spacing": {
                        "base_unit": "4px",
                        "scale": [
                          "4px",
                          "8px",
                          "12px",
                          "16px",
                          "24px",
                          "32px",
                          "40px",
                          "64px"
                        ]
                      },
                      "radius": {
                        "small": "4px",
                        "medium": "6px",
                        "large": "16px",
                        "full": true,
                        "scale": [
                          "4px",
                          "6px",
                          "16px",
                          "9999px"
                        ],
                        "button": "4px",
                        "input": "4px",
                        "card": "6px"
                      },
                      "shadows": {
                        "small": "rgba(23, 23, 23, 0.06) 0px 3px 6px 0px",
                        "medium": null,
                        "large": "rgba(23, 23, 23, 0.08) 0px 15px 35px 0px",
                        "scale": [
                          "rgba(23, 23, 23, 0.06) 0px 3px 6px 0px",
                          "rgba(23, 23, 23, 0.08) 0px 15px 35px 0px"
                        ]
                      },
                      "borders": {
                        "width": "1px",
                        "color": "#E5EDF5"
                      },
                      "components": {
                        "button_primary": {
                          "background": "#533AFD",
                          "text_color": "#FFFFFF",
                          "border_color": null,
                          "border_radius": "4px",
                          "font_weight": 400,
                          "font_family": "sohne-var",
                          "font_size": "16px",
                          "height": "48px",
                          "padding": "15.5px 24px 16.5px",
                          "text_transform": null,
                          "letter_spacing": null,
                          "box_shadow": null
                        },
                        "button_secondary": null,
                        "input": null,
                        "card": {
                          "background": "#FFFFFF",
                          "border_color": null,
                          "border_width": null,
                          "border_radius": "6px",
                          "box_shadow": "rgba(50, 50, 93, 0.12) 0px 16px 32px 0px",
                          "padding": null
                        },
                        "link": {
                          "color": "#533AFD",
                          "text_decoration": "none",
                          "font_weight": 400
                        }
                      },
                      "breakpoints": [
                        "640px",
                        "768px",
                        "1024px"
                      ],
                      "css_variables": {
                        "--hds-color-accent-border-solid": "#533afd"
                      }
                    },
                    "exports": {
                      "css": ":root {\n  --color-primary: #533AFD;\n  --color-background: #FFFFFF;\n}\n",
                      "tailwind": {
                        "theme": {
                          "extend": {
                            "colors": {
                              "primary": "#533AFD",
                              "background": "#FFFFFF"
                            }
                          }
                        }
                      }
                    }
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/transaction": {
      "get": {
        "operationId": "lookupTransaction",
        "summary": "Identify a transaction's merchant",
        "description": "Reads a card transaction descriptor — a bank statement line — and names the merchant behind it: \"SQ *BLUE BOTTLE COFFE OAKLAND CA\" → Blue Bottle Coffee, `bluebottlecoffee.com`, paid through Square, in Oakland. Truncated words are completed, processor prefixes and store numbers dropped, and lines that are not purchases are said to be so (`person`, `transfer`, `fee`, `atm`, `refund`). The merchant's name is resolved to its website the way `/resolve` does it, and `logo_url` points at its logo on the logo CDN. `include_brand=true` adds its brand as `GET /brand` returns it.\n\n**Credit cost: 3 per lookup, 1 when the same line (with the same country and MCC) was looked up in the last 7 days**, plus 10 when `include_brand` returns a brand. Failures are never charged.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "The transaction line as the bank statement or card network shows it (1–200 characters).",
              "example": "SQ *BLUE BOTTLE COFFE OAKLAND CA"
            },
            "required": true,
            "description": "The transaction line as the bank statement or card network shows it (1–200 characters).",
            "name": "descriptor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Two-letter code of the country the card was used in. Helps tell local merchants apart.",
              "example": "US"
            },
            "required": false,
            "description": "Two-letter code of the country the card was used in. Helps tell local merchants apart.",
            "name": "country",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "The four-digit merchant category code, if your card data has it.",
              "example": "5814"
            },
            "required": false,
            "description": "The four-digit merchant category code, if your card data has it.",
            "name": "mcc",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Also return the merchant's brand — logos, colors, fonts — exactly as GET /brand would, when its website is found. Adds the /brand price (10 credits), charged only when a brand is returned. Can take several seconds for a site not seen before. Pass \"true\"."
            },
            "required": false,
            "description": "Also return the merchant's brand — logos, colors, fonts — exactly as GET /brand would, when its website is found. Adds the /brand price (10 credits), charged only when a brand is returned. Can take several seconds for a site not seen before. Pass \"true\".",
            "name": "include_brand",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The merchant, or what else the line is.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TransactionData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "descriptor": "SQ *BLUE BOTTLE COFFE OAKLAND CA",
                    "kind": "merchant",
                    "merchant": {
                      "name": "Blue Bottle Coffee",
                      "domain": "bluebottlecoffee.com",
                      "url": "https://bluebottlecoffee.com",
                      "confidence": 0.88,
                      "source": "live"
                    },
                    "candidates": [
                      {
                        "name": "Blue Bottle Coffee",
                        "domain": "bluebottlecoffee.com",
                        "url": "https://bluebottlecoffee.com",
                        "confidence": 0.88,
                        "source": "live"
                      }
                    ],
                    "payment_processor": "Square",
                    "location": {
                      "city": "Oakland",
                      "region": "CA",
                      "country": "US"
                    },
                    "category": "Coffee shop",
                    "logo_url": "https://logo.prefetch.io/bluebottlecoffee.com?token=pk_4f1c9e2b7a0d4c3e8b6a1f2d3c4b5a69",
                    "parsed_by": "model",
                    "warnings": []
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "lookupTransactionPost",
        "summary": "Identify a transaction's merchant (JSON body)",
        "description": "Reads a card transaction descriptor — a bank statement line — and names the merchant behind it: \"SQ *BLUE BOTTLE COFFE OAKLAND CA\" → Blue Bottle Coffee, `bluebottlecoffee.com`, paid through Square, in Oakland. Truncated words are completed, processor prefixes and store numbers dropped, and lines that are not purchases are said to be so (`person`, `transfer`, `fee`, `atm`, `refund`). The merchant's name is resolved to its website the way `/resolve` does it, and `logo_url` points at its logo on the logo CDN. `include_brand=true` adds its brand as `GET /brand` returns it.\n\n**Credit cost: 3 per lookup, 1 when the same line (with the same country and MCC) was looked up in the last 7 days**, plus 10 when `include_brand` returns a brand. Failures are never charged.\n\nThe same endpoint as `GET /transaction`, with its options as typed JSON.",
        "tags": [
          "Endpoints"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The merchant, or what else the line is.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TransactionData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "descriptor": "SQ *BLUE BOTTLE COFFE OAKLAND CA",
                    "kind": "merchant",
                    "merchant": {
                      "name": "Blue Bottle Coffee",
                      "domain": "bluebottlecoffee.com",
                      "url": "https://bluebottlecoffee.com",
                      "confidence": 0.88,
                      "source": "live"
                    },
                    "candidates": [
                      {
                        "name": "Blue Bottle Coffee",
                        "domain": "bluebottlecoffee.com",
                        "url": "https://bluebottlecoffee.com",
                        "confidence": 0.88,
                        "source": "live"
                      }
                    ],
                    "payment_processor": "Square",
                    "location": {
                      "city": "Oakland",
                      "region": "CA",
                      "country": "US"
                    },
                    "category": "Coffee shop",
                    "logo_url": "https://logo.prefetch.io/bluebottlecoffee.com?token=pk_4f1c9e2b7a0d4c3e8b6a1f2d3c4b5a69",
                    "parsed_by": "model",
                    "warnings": []
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/batch/{endpoint}": {
      "post": {
        "operationId": "createBatch",
        "summary": "Run an endpoint on many URLs",
        "description": "Runs `brand`, `enrich`, `company`, `classify`, `screenshot` or `styleguide` on up to 500 URLs or bare domains as one job, and returns its id immediately. Each URL is answered exactly as `GET /{endpoint}` would answer it — curated data first, then a live extraction — with `options` (that endpoint's own parameters) applied to every URL. Poll `GET /batch/{endpoint}/{id}` for progress and results, or pass a `webhook`: events are named `batch_{endpoint}.*` (`batch_enrich.page` per URL, `batch_enrich.completed` at the end).\n\n**Credit cost: nothing to submit, then the endpoint's own price per URL answered** (enrich 12, brand 10, styleguide 10, classify 5, company 5, screenshot 1). URLs that fail are never charged. A key whose balance cannot cover every URL is refused up front with `CREDITS_EXHAUSTED`. Webhooks are not available through RapidAPI.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "brand",
                "enrich",
                "company",
                "classify",
                "screenshot",
                "styleguide"
              ],
              "description": "What every URL is run through. /batch/scrape has its own page.",
              "example": "enrich"
            },
            "required": true,
            "description": "What every URL is run through. /batch/scrape has its own page.",
            "name": "endpoint",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchBody"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/BatchJobData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_7c2e9a4b1d0f4e6a8b3c5d7e9f1a2b3c",
                    "status": "pending",
                    "endpoint": "enrich",
                    "url_count": 3,
                    "invalid_urls": [],
                    "created_at": "2026-10-13T09:14:03.221Z",
                    "expires_at": "2026-10-14T09:14:03.221Z"
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/batch/{endpoint}/{id}": {
      "get": {
        "operationId": "getBatchStatus",
        "summary": "Batch status and results",
        "description": "Progress plus a page of answered URLs, in completion order: each carries what `GET /{endpoint}` returns for it, plus `ok`, `error` and `error_code`. Follow `next` until it is null. Results stay readable for 24 hours. URLs are charged as they complete — here, or when the batch ends — never twice.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "brand",
                "enrich",
                "company",
                "classify",
                "screenshot",
                "styleguide"
              ],
              "description": "What every URL is run through. /batch/scrape has its own page.",
              "example": "enrich"
            },
            "required": true,
            "description": "What every URL is run through. /batch/scrape has its own page.",
            "name": "endpoint",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "The id returned when the job was created.",
              "example": "crw_9f2c1a7b4e0d4c3a"
            },
            "required": true,
            "description": "The id returned when the job was created.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "Page rows to skip — the cursor for paging through a crawl's results.",
              "example": "0"
            },
            "required": false,
            "description": "Page rows to skip — the cursor for paging through a crawl's results.",
            "name": "skip",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Page rows to return per request.",
              "example": "25"
            },
            "required": false,
            "description": "Page rows to return per request.",
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Batch status and a page of results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/BatchStatusData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_7c2e9a4b1d0f4e6a8b3c5d7e9f1a2b3c",
                    "status": "completed",
                    "url": "https://stripe.com",
                    "total": 3,
                    "completed": 3,
                    "failed": 0,
                    "credits_used": 36,
                    "created_at": "2026-10-13T09:14:03.221Z",
                    "started_at": "2026-10-13T09:14:04.010Z",
                    "finished_at": "2026-10-13T09:14:41.512Z",
                    "expires_at": "2026-10-14T09:14:03.221Z",
                    "error": null,
                    "kind": "batch",
                    "endpoint": "enrich",
                    "next": null,
                    "data": [
                      {
                        "url": "https://stripe.com",
                        "depth": 0,
                        "status_code": 200,
                        "ok": true,
                        "error": null,
                        "error_code": null,
                        "domain": "stripe.com",
                        "brand": {
                          "colors": {
                            "brand_colors": [
                              {
                                "color": "rgb(99, 91, 255)",
                                "hex": "#635BFF",
                                "name": "Medium Slate Blue"
                              }
                            ]
                          }
                        },
                        "company": {
                          "name": "Stripe, Inc.",
                          "emails": [],
                          "addresses": []
                        },
                        "classification": {
                          "iab_id": "IAB3-4",
                          "category": "Business"
                        }
                      }
                    ]
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Batch not found or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "cancelBatch",
        "summary": "Cancel a batch",
        "description": "Stops a running batch. URLs already answered stay readable until it expires, and are charged.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "brand",
                "enrich",
                "company",
                "classify",
                "screenshot",
                "styleguide"
              ],
              "description": "What every URL is run through. /batch/scrape has its own page.",
              "example": "enrich"
            },
            "required": true,
            "description": "What every URL is run through. /batch/scrape has its own page.",
            "name": "endpoint",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "The id returned when the job was created.",
              "example": "crw_9f2c1a7b4e0d4c3a"
            },
            "required": true,
            "description": "The id returned when the job was created.",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Batch cancelled (or already finished).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlStatusData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_7c2e9a4b1d0f4e6a8b3c5d7e9f1a2b3c",
                    "status": "cancelled",
                    "url": "https://stripe.com",
                    "total": 3,
                    "completed": 3,
                    "failed": 0,
                    "credits_used": 36,
                    "created_at": "2026-10-13T09:14:03.221Z",
                    "started_at": "2026-10-13T09:14:04.010Z",
                    "finished_at": "2026-10-13T09:14:41.512Z",
                    "expires_at": "2026-10-14T09:14:03.221Z",
                    "error": null,
                    "kind": "batch",
                    "endpoint": "enrich",
                    "next": null,
                    "data": []
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Batch not found or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/batch/{endpoint}/{id}/errors": {
      "get": {
        "operationId": "getBatchErrors",
        "summary": "Batch errors",
        "description": "The URLs that failed, oldest first, each with its `error_code`. Free.",
        "tags": [
          "Endpoints"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "brand",
                "enrich",
                "company",
                "classify",
                "screenshot",
                "styleguide"
              ],
              "description": "What every URL is run through. /batch/scrape has its own page.",
              "example": "enrich"
            },
            "required": true,
            "description": "What every URL is run through. /batch/scrape has its own page.",
            "name": "endpoint",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "The id returned when the job was created.",
              "example": "crw_9f2c1a7b4e0d4c3a"
            },
            "required": true,
            "description": "The id returned when the job was created.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "Failed pages to skip, for paging.",
              "example": "0"
            },
            "required": false,
            "description": "Failed pages to skip, for paging.",
            "name": "skip",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Failed pages per response (1–100). Default: 100.",
              "example": "100"
            },
            "required": false,
            "description": "Failed pages per response (1–100). Default: 100.",
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The URLs that failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/CrawlErrorsData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "crw_7c2e9a4b1d0f4e6a8b3c5d7e9f1a2b3c",
                    "status": "completed",
                    "failed": [],
                    "failed_total": 0,
                    "skipped": {},
                    "next": null
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Batch not found or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/logo/token": {
      "get": {
        "operationId": "getLogoToken",
        "summary": "Get your logo CDN token",
        "description": "Your organisation's publishable logo token, with this month's quota and use.\n\nLogos are served from `https://logo.prefetch.io/<domain>?token=<token>` — put that URL straight in an `<img>` tag. Optional parameters: `size` (16–512, default 128), `format` (`png`, `webp`, `jpeg`), `theme` (`light` or `dark`: the background for JPEG), `greyscale`, and `fallback` (`monogram`, the default letter mark; `404`; or `transparent`).\n\nLogo requests cost **no credits**: each plan includes a monthly quota (Free 100,000 · Starter 250,000 · Pro 1,000,000 · Growth 3,000,000 · Scale 10,000,000). Not available through RapidAPI.",
        "tags": [
          "Endpoints"
        ],
        "responses": {
          "200": {
            "description": "Your publishable token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LogoTokenData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "token": "pk_4f1c9e2b7a0d4c3e8b6a1f2d3c4b5a69",
                    "cdn_url": "https://logo.prefetch.io",
                    "example": "https://logo.prefetch.io/stripe.com?token=pk_4f1c9e2b7a0d4c3e8b6a1f2d3c4b5a69",
                    "quota": 100000,
                    "used": 1234,
                    "period": "2026-10-01"
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/logo/token/rotate": {
      "post": {
        "operationId": "rotateLogoToken",
        "summary": "Rotate your logo CDN token",
        "description": "Replaces your organisation's logo token. The old one stops working at once — and with it every logo already embedded with it — so rotate only a token someone else is using against your quota.",
        "tags": [
          "Endpoints"
        ],
        "responses": {
          "200": {
            "description": "The new token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LogoTokenData"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "token": "pk_9a8b7c6d5e4f40312a1b2c3d4e5f6a7b",
                    "cdn_url": "https://logo.prefetch.io",
                    "example": "https://logo.prefetch.io/stripe.com?token=pk_9a8b7c6d5e4f40312a1b2c3d4e5f6a7b",
                    "quota": 100000,
                    "used": 0,
                    "period": "2026-10-01"
                  },
                  "meta": {
                    "requestId": "6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b",
                    "durationMs": 1840
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Revoked key, expired key, blocked URL, or credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate or concurrency limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable — retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "monitor.page": {
      "post": {
        "operationId": "monitorPageEvent",
        "summary": "monitor.page",
        "description": "Sent for each page that changed, appeared, was removed, or started failing. Not sent for the first check's baseline, or for changes the judge ruled not meaningful.",
        "parameters": [
          {
            "name": "X-Prefetch-Event",
            "in": "header",
            "required": true,
            "description": "The event type.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Prefetch-Delivery",
            "in": "header",
            "required": true,
            "description": "The delivery id — the same as `id` in the body, and stable across retries.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Prefetch-Signature",
            "in": "header",
            "required": true,
            "description": "`t=<unix seconds>,v1=<hex>`, where `hex` is HMAC-SHA256 of `\"<t>.<raw body>\"` keyed with the monitor's `webhook.secret`.",
            "schema": {
              "type": "string",
              "example": "t=1760248862,v1=5f2b8c..."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorPageEvent"
              },
              "example": {
                "success": true,
                "type": "monitor.page",
                "id": "whd_5c1e9a2b7d3f4e6a8b0c2d4e6f8a1b3c",
                "created_at": "2026-10-12T06:01:02.481Z",
                "monitor_id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                "monitor_name": "Competitor pricing",
                "check_id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                "data": {
                  "target_id": "tgt_8d1e0f2a3b4c5d6e",
                  "url": "https://example.com/pricing",
                  "status": "changed",
                  "status_code": 200,
                  "error": null,
                  "title": "Pricing — Example",
                  "previous_check_id": "chk_51b0c2d3e4f5a6b7c8d9e0f1a2b3c4d5",
                  "is_meaningful": true,
                  "judgment": {
                    "meaningful": true,
                    "confidence": "high",
                    "reason": "The Starter plan's price went from $19 to $24 a month.",
                    "meaningful_changes": [
                      {
                        "type": "changed",
                        "before": "$19/mo",
                        "after": "$24/mo",
                        "reason": "A plan price changed."
                      }
                    ]
                  },
                  "diff": {
                    "fields": {
                      "plans[0].price": {
                        "previous": "$19/mo",
                        "current": "$24/mo",
                        "change": "changed"
                      }
                    },
                    "changed_fields": 1
                  },
                  "snapshot": {
                    "json": {
                      "plans": [
                        {
                          "name": "Starter",
                          "price": "$24/mo",
                          "features": [
                            "3 seats",
                            "Email support"
                          ]
                        },
                        {
                          "name": "Pro",
                          "price": "$49/mo",
                          "features": [
                            "Unlimited seats",
                            "SSO"
                          ]
                        }
                      ]
                    }
                  }
                },
                "metadata": {
                  "env": "production"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Answer any 2xx within 10 seconds. Anything else, or no answer, is retried after 1, 5 and 15 minutes."
          }
        }
      }
    },
    "monitor.check.completed": {
      "post": {
        "operationId": "monitorCheckCompletedEvent",
        "summary": "monitor.check.completed",
        "description": "Sent once per check that ran, and once when a monitor starts being skipped for lack of credits.",
        "parameters": [
          {
            "name": "X-Prefetch-Event",
            "in": "header",
            "required": true,
            "description": "The event type.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Prefetch-Delivery",
            "in": "header",
            "required": true,
            "description": "The delivery id — the same as `id` in the body, and stable across retries.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Prefetch-Signature",
            "in": "header",
            "required": true,
            "description": "`t=<unix seconds>,v1=<hex>`, where `hex` is HMAC-SHA256 of `\"<t>.<raw body>\"` keyed with the monitor's `webhook.secret`.",
            "schema": {
              "type": "string",
              "example": "t=1760248862,v1=5f2b8c..."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorCheckCompletedEvent"
              },
              "example": {
                "success": true,
                "type": "monitor.check.completed",
                "id": "whd_7a9c1e3b5d7f9a2c4e6b8d0f2a4c6e8b",
                "created_at": "2026-10-12T06:01:27.944Z",
                "monitor_id": "mon_3f9a1c2b7d4e4f6a8b0c1d2e3f4a5b6c",
                "monitor_name": "Competitor pricing",
                "check_id": "chk_8e2d4f6a1b3c4d5e6f7a8b9c0d1e2f3a",
                "data": {
                  "status": "completed",
                  "trigger": "scheduled",
                  "summary": {
                    "total_pages": 19,
                    "same": 16,
                    "new": 1,
                    "changed": 1,
                    "removed": 1,
                    "error": 0
                  },
                  "started_at": "2026-10-12T06:00:04.112Z",
                  "finished_at": "2026-10-12T06:01:27.930Z",
                  "actual_credits": 24,
                  "error": null
                },
                "metadata": {
                  "env": "production"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Answer any 2xx within 10 seconds. Anything else, or no answer, is retried after 1, 5 and 15 minutes."
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Endpoints",
      "description": "Data extraction endpoints. All require authentication and consume credits."
    },
    {
      "name": "Health",
      "description": "Health and readiness probes. No authentication required."
    }
  ]
}
