{
    "openapi": "3.0.3",
    "info": {
        "title": "HTML Parser \u2014 Ksty.ch",
        "version": "1.0",
        "description": "Parse an HTML document into structured content \u2014 metadata, Open Graph, headings, links, images and readable text.\n\n# HTML Parser API\n\nTurns a raw HTML document into clean, structured JSON. Give it the HTML directly with `html`, or hand it a `url` and it fetches the page for you, and it returns the pieces you normally have to write a scraper for \u2014 the title and meta description, Open Graph and Twitter card tags, the canonical URL and favicon, every heading, link and image, and the readable plain-text body with a word count and reading-time estimate.\n\nParsing runs locally against a real HTML parser, so malformed markup, unclosed tags and messy real-world pages are handled the same way a browser would tolerate them \u2014 you get structure back, not an error.\n\n## Two ways to call it\n\nSupply the markup directly:\n\n```\nPOST /api/v1/html-parser\nX-Api-Key: ksty_test_...\nContent-Type: application/json\n\n{\"html\": \"<html><head><title>Hello</title></head><body><h1>Hi</h1><p>World</p></body></html>\"}\n```\n\n\u2026or let the API fetch the page (relative links are resolved against the fetched URL automatically):\n\n```\n{\"url\": \"https://example.com\"}\n```\n\n```json\n{\n  \"title\": \"Hello\",\n  \"lang\": \"\",\n  \"description\": \"\",\n  \"canonical\": \"\",\n  \"favicon\": \"\",\n  \"meta\": {},\n  \"opengraph\": {},\n  \"twitter\": {},\n  \"headings\": { \"h1\": [\"Hi\"] },\n  \"links\": [],\n  \"images\": [],\n  \"text\": \"Hi World\",\n  \"word_count\": 2,\n  \"reading_time_min\": 1\n}\n```\n\n## Endpoints\n\nThe root endpoint returns everything. Three focused endpoints return only one section each, so you pay for and transfer just the part you need:\n\n- `html-parser` \u2014 the full parse (all sections above).\n- `html-parser.metadata` \u2014 title, language, description, canonical, favicon, and the raw `meta` / `opengraph` / `twitter` maps. Ideal for building link previews.\n- `html-parser.links` \u2014 every `<a href>` as `{url, text}`, plus every `<img>` as `{src, alt}`, with relative URLs resolved to absolute.\n- `html-parser.text` \u2014 the readable plain-text body only, with `word_count` and `reading_time_min`.\n\n## Parameters\n\n- `html` \u2014 the HTML document to parse. Either this or `url` is required; if both are sent, `html` wins.\n- `url` \u2014 an `http(s)` URL to fetch and parse. The fetch is a single GET with an 8-second timeout and a 3 MB size cap; URLs that resolve to private or reserved IP addresses are refused (SSRF protection).\n- `base_url` \u2014 a base used to resolve relative links and images to absolute URLs. Defaults to `url` when you fetch, or the document's own `<base href>` when present.\n\n## Link resolution\n\nRelative links (`/about`, `../pricing`, `logo.png`) are turned into absolute URLs whenever a base is available \u2014 from `base_url`, the fetched `url`, or a `<base href>` in the document, in that order. When no base can be determined the original relative value is returned unchanged.\n\n## Readable text\n\n`text` is the visible body text with `<script>`, `<style>` and `<noscript>` content removed and whitespace collapsed to single spaces \u2014 the same text a reader would see, not the raw markup. `word_count` counts whitespace-separated tokens and `reading_time_min` is `ceil(word_count / 200)`.\n\n## Limits\n\n- **No JavaScript.** The parser reads the HTML as delivered; content injected by client-side scripts after load is not present. For script-rendered pages, fetch the rendered HTML yourself and pass it as `html`.\n- **Fetch is best-effort.** A URL that times out, is too large, or resolves to a blocked address returns a `fetch_failed` error and is **not** billed.\n- **One document per call.** There is no crawling or link-following; each call parses exactly the document you provide.\n\n## When to use it\n\n- Building link previews / unfurls from a URL (title, description, OG image).\n- Extracting the readable article text from a page for indexing or summarisation.\n- Auditing a page's links and images, or its SEO metadata, without writing a parser per site.",
        "x-credit-cost": 1,
        "x-free-grant": {
            "type": "monthly",
            "amount": 50
        },
        "x-sandbox": true
    },
    "servers": [
        {
            "url": "https://ksty.ch/api/v1"
        }
    ],
    "security": [
        {
            "ApiKeyAuth": []
        }
    ],
    "paths": {
        "/html-parser": {
            "get": {
                "operationId": "html-parser_get",
                "summary": "Parse an HTML document into all structured sections",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "title": "Hello",
                                    "lang": "en",
                                    "description": "",
                                    "canonical": "",
                                    "favicon": "",
                                    "meta": [],
                                    "opengraph": [],
                                    "twitter": [],
                                    "headings": {
                                        "h1": [
                                            "Hi"
                                        ]
                                    },
                                    "links": [],
                                    "images": [],
                                    "text": "Hi World",
                                    "word_count": 2,
                                    "reading_time_min": 1
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "title": {
                                            "type": "string",
                                            "description": "Contents of <title>, whitespace-normalised."
                                        },
                                        "lang": {
                                            "type": "string",
                                            "description": "The <html lang> attribute, empty when absent."
                                        },
                                        "description": {
                                            "type": "string",
                                            "description": "meta description, falling back to og:description."
                                        },
                                        "canonical": {
                                            "type": "string",
                                            "description": "Canonical URL, resolved to absolute."
                                        },
                                        "favicon": {
                                            "type": "string",
                                            "description": "First icon link, resolved to absolute."
                                        },
                                        "meta": {
                                            "type": "object",
                                            "description": "Every named <meta> tag as name \u2192 content. Tags with empty content are dropped."
                                        },
                                        "opengraph": {
                                            "type": "object",
                                            "description": "og:* properties with the prefix stripped, so og:image arrives as \"image\"."
                                        },
                                        "twitter": {
                                            "type": "object",
                                            "description": "twitter:* tags with the prefix stripped."
                                        },
                                        "headings": {
                                            "type": "object",
                                            "description": "h1\u2013h6 \u2192 array of heading texts, in document order. Levels with no headings are omitted rather than sent empty."
                                        },
                                        "links": {
                                            "type": "array",
                                            "description": "Every <a href> as {url, text}, absolutised. Fragment-only and javascript: links are skipped."
                                        },
                                        "images": {
                                            "type": "array",
                                            "description": "Every <img src> as {src, alt}, absolutised."
                                        },
                                        "text": {
                                            "type": "string",
                                            "description": "Readable body text with script, style, nav and other non-content nodes removed."
                                        },
                                        "word_count": {
                                            "type": "integer",
                                            "description": "Words in \"text\"."
                                        },
                                        "reading_time_min": {
                                            "type": "integer",
                                            "description": "Estimated reading time in whole minutes, never less than 1."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "description": "The root endpoint runs every extractor and merges the results, so one call gives you metadata,\nheadings, links, images and readable text together. If you only need one of those, the dedicated\nendpoints below do the same work for the same price but return a much smaller payload \u2014 worth using\nwhen you are parsing at volume.",
                "parameters": [
                    {
                        "name": "html",
                        "in": "query",
                        "required": false,
                        "description": "The HTML document to parse (required unless url is given). Wins over \"url\" when both are sent.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "url",
                        "in": "query",
                        "required": false,
                        "description": "An http(s) URL to fetch and parse instead of passing html",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "base_url",
                        "in": "query",
                        "required": false,
                        "description": "Base URL relative links and images resolve against. Defaults to \"url\" when fetching, then to a <base href> in the document.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "post": {
                "operationId": "html-parser_post",
                "summary": "Parse an HTML document into all structured sections",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "title": "Hello",
                                    "lang": "en",
                                    "description": "",
                                    "canonical": "",
                                    "favicon": "",
                                    "meta": [],
                                    "opengraph": [],
                                    "twitter": [],
                                    "headings": {
                                        "h1": [
                                            "Hi"
                                        ]
                                    },
                                    "links": [],
                                    "images": [],
                                    "text": "Hi World",
                                    "word_count": 2,
                                    "reading_time_min": 1
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "title": {
                                            "type": "string",
                                            "description": "Contents of <title>, whitespace-normalised."
                                        },
                                        "lang": {
                                            "type": "string",
                                            "description": "The <html lang> attribute, empty when absent."
                                        },
                                        "description": {
                                            "type": "string",
                                            "description": "meta description, falling back to og:description."
                                        },
                                        "canonical": {
                                            "type": "string",
                                            "description": "Canonical URL, resolved to absolute."
                                        },
                                        "favicon": {
                                            "type": "string",
                                            "description": "First icon link, resolved to absolute."
                                        },
                                        "meta": {
                                            "type": "object",
                                            "description": "Every named <meta> tag as name \u2192 content. Tags with empty content are dropped."
                                        },
                                        "opengraph": {
                                            "type": "object",
                                            "description": "og:* properties with the prefix stripped, so og:image arrives as \"image\"."
                                        },
                                        "twitter": {
                                            "type": "object",
                                            "description": "twitter:* tags with the prefix stripped."
                                        },
                                        "headings": {
                                            "type": "object",
                                            "description": "h1\u2013h6 \u2192 array of heading texts, in document order. Levels with no headings are omitted rather than sent empty."
                                        },
                                        "links": {
                                            "type": "array",
                                            "description": "Every <a href> as {url, text}, absolutised. Fragment-only and javascript: links are skipped."
                                        },
                                        "images": {
                                            "type": "array",
                                            "description": "Every <img src> as {src, alt}, absolutised."
                                        },
                                        "text": {
                                            "type": "string",
                                            "description": "Readable body text with script, style, nav and other non-content nodes removed."
                                        },
                                        "word_count": {
                                            "type": "integer",
                                            "description": "Words in \"text\"."
                                        },
                                        "reading_time_min": {
                                            "type": "integer",
                                            "description": "Estimated reading time in whole minutes, never less than 1."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "description": "The root endpoint runs every extractor and merges the results, so one call gives you metadata,\nheadings, links, images and readable text together. If you only need one of those, the dedicated\nendpoints below do the same work for the same price but return a much smaller payload \u2014 worth using\nwhen you are parsing at volume.",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "html": {
                                        "type": "string",
                                        "description": "The HTML document to parse (required unless url is given). Wins over \"url\" when both are sent.",
                                        "example": "<html><head><title>Hello</title></head><body><h1>Hi</h1><p>Hi World</p></body></html>"
                                    },
                                    "url": {
                                        "type": "string",
                                        "description": "An http(s) URL to fetch and parse instead of passing html",
                                        "example": null
                                    },
                                    "base_url": {
                                        "type": "string",
                                        "description": "Base URL relative links and images resolve against. Defaults to \"url\" when fetching, then to a <base href> in the document.",
                                        "example": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/html-parser.metadata": {
            "get": {
                "operationId": "html-parser_metadata_get",
                "summary": "Extract page metadata only \u2014 title, description, canonical, favicon, Open Graph and Twitter tags",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "title": "Hello",
                                    "lang": "",
                                    "description": "",
                                    "canonical": "",
                                    "favicon": "",
                                    "meta": [],
                                    "opengraph": {
                                        "image": "/card.png"
                                    },
                                    "twitter": []
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "title": {
                                            "type": "string",
                                            "description": "Contents of <title>, whitespace-normalised."
                                        },
                                        "lang": {
                                            "type": "string",
                                            "description": "The <html lang> attribute, empty when absent."
                                        },
                                        "description": {
                                            "type": "string",
                                            "description": "meta description, falling back to og:description."
                                        },
                                        "canonical": {
                                            "type": "string",
                                            "description": "Canonical URL, resolved to absolute."
                                        },
                                        "favicon": {
                                            "type": "string",
                                            "description": "First icon link, resolved to absolute."
                                        },
                                        "meta": {
                                            "type": "object",
                                            "description": "Every named <meta> tag as name \u2192 content."
                                        },
                                        "opengraph": {
                                            "type": "object",
                                            "description": "og:* properties with the prefix stripped \u2014 the set social cards are built from."
                                        },
                                        "twitter": {
                                            "type": "object",
                                            "description": "twitter:* tags with the prefix stripped."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "html",
                        "in": "query",
                        "required": false,
                        "description": "The HTML document to parse (required unless url is given)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "url",
                        "in": "query",
                        "required": false,
                        "description": "An http(s) URL to fetch and parse instead of passing html",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "base_url",
                        "in": "query",
                        "required": false,
                        "description": "Base URL the canonical and favicon resolve against",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "post": {
                "operationId": "html-parser_metadata_post",
                "summary": "Extract page metadata only \u2014 title, description, canonical, favicon, Open Graph and Twitter tags",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "title": "Hello",
                                    "lang": "",
                                    "description": "",
                                    "canonical": "",
                                    "favicon": "",
                                    "meta": [],
                                    "opengraph": {
                                        "image": "/card.png"
                                    },
                                    "twitter": []
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "title": {
                                            "type": "string",
                                            "description": "Contents of <title>, whitespace-normalised."
                                        },
                                        "lang": {
                                            "type": "string",
                                            "description": "The <html lang> attribute, empty when absent."
                                        },
                                        "description": {
                                            "type": "string",
                                            "description": "meta description, falling back to og:description."
                                        },
                                        "canonical": {
                                            "type": "string",
                                            "description": "Canonical URL, resolved to absolute."
                                        },
                                        "favicon": {
                                            "type": "string",
                                            "description": "First icon link, resolved to absolute."
                                        },
                                        "meta": {
                                            "type": "object",
                                            "description": "Every named <meta> tag as name \u2192 content."
                                        },
                                        "opengraph": {
                                            "type": "object",
                                            "description": "og:* properties with the prefix stripped \u2014 the set social cards are built from."
                                        },
                                        "twitter": {
                                            "type": "object",
                                            "description": "twitter:* tags with the prefix stripped."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "html": {
                                        "type": "string",
                                        "description": "The HTML document to parse (required unless url is given)",
                                        "example": "<html><head><title>Hello</title><meta property=\"og:image\" content=\"/card.png\"></head></html>"
                                    },
                                    "url": {
                                        "type": "string",
                                        "description": "An http(s) URL to fetch and parse instead of passing html",
                                        "example": null
                                    },
                                    "base_url": {
                                        "type": "string",
                                        "description": "Base URL the canonical and favicon resolve against",
                                        "example": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/html-parser.links": {
            "get": {
                "operationId": "html-parser_links_get",
                "summary": "Extract every link and image, with relative URLs resolved to absolute",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "links": [
                                        {
                                            "url": "https://example.com/about",
                                            "text": "About"
                                        }
                                    ],
                                    "images": [
                                        {
                                            "src": "https://example.com/logo.png",
                                            "alt": "Logo"
                                        }
                                    ]
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "links": {
                                            "type": "array",
                                            "description": "Every <a href> as {url, text}. Fragment-only (#foo) and javascript: hrefs are skipped; duplicates are kept, in document order."
                                        },
                                        "images": {
                                            "type": "array",
                                            "description": "Every <img src> as {src, alt}."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "html",
                        "in": "query",
                        "required": false,
                        "description": "The HTML document to parse (required unless url is given)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "url",
                        "in": "query",
                        "required": false,
                        "description": "An http(s) URL to fetch and parse instead of passing html",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "base_url",
                        "in": "query",
                        "required": false,
                        "description": "Base URL relative links and images resolve against",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "post": {
                "operationId": "html-parser_links_post",
                "summary": "Extract every link and image, with relative URLs resolved to absolute",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "links": [
                                        {
                                            "url": "https://example.com/about",
                                            "text": "About"
                                        }
                                    ],
                                    "images": [
                                        {
                                            "src": "https://example.com/logo.png",
                                            "alt": "Logo"
                                        }
                                    ]
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "links": {
                                            "type": "array",
                                            "description": "Every <a href> as {url, text}. Fragment-only (#foo) and javascript: hrefs are skipped; duplicates are kept, in document order."
                                        },
                                        "images": {
                                            "type": "array",
                                            "description": "Every <img src> as {src, alt}."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "html": {
                                        "type": "string",
                                        "description": "The HTML document to parse (required unless url is given)",
                                        "example": "<a href=\"/about\">About</a><img src=\"/logo.png\" alt=\"Logo\">"
                                    },
                                    "url": {
                                        "type": "string",
                                        "description": "An http(s) URL to fetch and parse instead of passing html",
                                        "example": null
                                    },
                                    "base_url": {
                                        "type": "string",
                                        "description": "Base URL relative links and images resolve against",
                                        "example": "https://example.com"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/html-parser.text": {
            "get": {
                "operationId": "html-parser_text_get",
                "summary": "Extract the readable plain-text body with word count and reading time",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "text": "Hi World",
                                    "word_count": 2,
                                    "reading_time_min": 1
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "text": {
                                            "type": "string",
                                            "description": "Readable text with script, style and other non-content nodes stripped first, so nothing from the page chrome leaks in."
                                        },
                                        "word_count": {
                                            "type": "integer",
                                            "description": "Words in \"text\"."
                                        },
                                        "reading_time_min": {
                                            "type": "integer",
                                            "description": "Estimated minutes to read, rounded up and never below 1."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "html",
                        "in": "query",
                        "required": false,
                        "description": "The HTML document to parse (required unless url is given)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "url",
                        "in": "query",
                        "required": false,
                        "description": "An http(s) URL to fetch and parse instead of passing html",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "post": {
                "operationId": "html-parser_text_post",
                "summary": "Extract the readable plain-text body with word count and reading time",
                "x-credit-cost": 1,
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "example": {
                                    "text": "Hi World",
                                    "word_count": 2,
                                    "reading_time_min": 1
                                },
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "text": {
                                            "type": "string",
                                            "description": "Readable text with script, style and other non-content nodes stripped first, so nothing from the page chrome leaks in."
                                        },
                                        "word_count": {
                                            "type": "integer",
                                            "description": "Words in \"text\"."
                                        },
                                        "reading_time_min": {
                                            "type": "integer",
                                            "description": "Estimated minutes to read, rounded up and never below 1."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "invalid_request \u2014 Neither an \"html\" string nor a \"url\" was supplied (or \"html\" was blank).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing or invalid API key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Insufficient credits \u2014 nothing is charged and the API is never reached",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "The key is not scoped to this API, or a test key was used on an API without sandbox support",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded for this key",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "fetch_failed \u2014 A \"url\" was given but could not be retrieved: DNS failure, timeout, non-2xx status, a non-HTML content type, or a blocked address (private and loopback ranges are refused on every redirect hop).\n\nThe API failed after being charged; credits are refunded automatically",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "html": {
                                        "type": "string",
                                        "description": "The HTML document to parse (required unless url is given)",
                                        "example": "<body><script>ignored()</script><p>Hi World</p></body>"
                                    },
                                    "url": {
                                        "type": "string",
                                        "description": "An http(s) URL to fetch and parse instead of passing html",
                                        "example": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "ApiKeyAuth": {
                "type": "apiKey",
                "in": "header",
                "name": "X-Api-Key"
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "string",
                                "description": "Stable machine-readable code \u2014 branch on this, never on the message."
                            },
                            "message": {
                                "type": "string"
                            },
                            "request_id": {
                                "type": "string"
                            }
                        }
                    }
                }
            }
        }
    }
}