{"openapi":"3.0.3","info":{"title":"UnblockingAPI","version":"1.0.0","description":"Web unblocking / scraping API. Fetch any URL and get clean HTML back — with\noptional JavaScript rendering, residential-proxy geo-targeting, and wait\nstrategies for dynamic pages.\n\n## Authentication\nEvery request needs your API key, sent any one of these ways:\n- `X-Api-Key: <key>` header\n- `Authorization: Bearer <key>` header\n- `?key=<key>` query parameter (handy for quick browser tests)\n\n## Credits\nEvery *successful* request (a 2xx, or a delivered 404) costs 1 credit —\nrendered or not, cache hits included. Failed requests are free.\nSubscriptions add credits every month at a lower price per credit;\nanyone can buy a credit pack. When your balance hits zero the API\nreturns `402` until you top up.\n\n## Concurrency\nEach plan allows a number of requests in flight at once (5 on Pay as\nyou Go, more on every paid tier). Going over returns `429` — retry the\nrequest once one of your in-flight requests finishes.\n"},"servers":[{"url":"https://api.unblockingapi.com"}],"tags":[{"name":"Unblock","description":"Fetch any URL — raw HTTP or full browser render."},{"name":"Templates","description":"The public template catalogue. Keyless."}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"ApiKeyQuery":[]}],"paths":{"/unblock":{"get":{"tags":["Unblock"],"summary":"Fetch a URL","description":"Returns the page HTML, or structured JSON when you name a template with `template` (see below). Both GET and POST are supported; POST takes a JSON body.\n\n## Templates\n\nPass `template=<name>` to get structured JSON (`response_format: \"json\"`)\ninstead of HTML, with `api_name` naming the template used. The template\nsupplies the fetch settings its parser needs, which may include a browser\nrender — billed like any render request.\n\nNothing is applied automatically: without `template` you always get the\nraw page. An unknown template, or one that is not yours and not public,\nis a `404`.\n\n### Pinning a version\n\nEvery save its author makes takes a template to the next version, and\n`template_version` in the response says which one answered. Pin one with\n`template=someone/their-template@3` and you keep getting exactly what\nversion 3 returned, however much its author edits afterwards — which is\nwhat lets you build against a shape and leave it alone. Unpinned, you\nalways follow the latest. A version above the latest is a `404`; a\ntemplate its author unpublishes stops serving its old versions too.\n\nIf a parser fails (the site changed its markup), you get the raw HTML\nback with `parse_error: true` rather than an error.\n\nAnyone can build a template in the editor (editor.unblockingapi.com) and publish it here.\n\n| Template | Built for | Fetched | Source | Returns |\n|---|---|---|---|---|\n| `kjellberg/ahrefs-website-authority-checker` | ahrefs.com/website-authority-checker | rendered, from ES | Community | Check the “authority” of your domain (as measured by Ahrefs). Returns all the statistics from the Ahrefs free tool. |\n| `kjellberg/avanza-borsen-idag` | avanza.se/borsen-idag.html | rendered | Community |  |\n| `kjellberg/bing` | bing.com/search | plain HTTP | Community | Parse search results from Bing |\n| `kjellberg/eniro-foretag` | eniro.se/*/f%C3%B6retag | plain HTTP, from SE | Community |  |\n| `kjellberg/google-search` | google.com/search | rendered | Community |  |\n| `kjellberg/hemnet-landing-page` | hemnet.se | rendered | Community | List latest properties and top ranked properties in different categories from Hemnet.se's landing page. |\n| `kjellberg/hetzner-auction` | hetzner.com/sb | rendered, from DE | Community | List available servers in the Hetzner auction |\n| `kjellberg/hi-homes-search` | hihomes.es/property-for-sale | plain HTTP | Community | Search properties in Costa del Sol |\n| `kjellberg/idealista-search` | idealista.com/*/** | rendered, from ES | Community | Get all listings from a search page on Idealista.com. |\n| `kjellberg/marbella-living-property` | marbellaliving.com | plain HTTP | Community | Get data from a property listing on Marbella Living's website. |\n| `kjellberg/marbella-living-search` | marbellaliving.com/search.php | plain HTTP, from ES | Community | API for Marbella Living property listings. Search with any parameter. |\n| `kjellberg/mempool-space-block-view` | mempool.space/block/** | rendered | Community |  |\n| `kjellberg/reddit-post` | reddit.com/r/** | rendered | Community | Parses any public Reddit post. Just paste the link and it will return JSON. Full post + first level comments.  |\n| `kjellberg/serneholt-estates-search` | serneholtestate.com/properties/** | plain HTTP, from ES | Community |  |\n| `kjellberg/sigma-world-category` | sigma.world/latest-news/** | plain HTTP | Community | Receives a list of article info and urls. |\n","responses":{"200":{"description":"Success — the target returned a 2xx. Body carries the fetched content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Out of credits (or the account is still provisioning). Buy a credit pack or subscribe at https://unblockingapi.com/billing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Target returned 404. Treated as a successful result (status is \"succeeded\"), not a failure. A 404 with only an `error` field instead means `template` named no template you can use.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"422":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests in flight for this API key — over your plan's concurrency limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The target site failed — any non-2xx/404 status, a block, a captcha wall, or a render failure. The target's real status is in `http_response_code` and the reason in `error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"503":{"description":"Service temporarily unavailable — our proxy pool is exhausted or the render backend is unreachable/saturated. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"504":{"description":"Timed out waiting for the target or the render backend.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}}},"operationId":"unblockGet","parameters":[{"name":"url","in":"query","required":true,"description":"URL to fetch. Must be http(s) and not point at a media/binary file.","schema":{"type":"string","format":"uri","example":"https://example.com"}},{"name":"render","in":"query","required":false,"description":"Whether to render with a real browser (executes JavaScript). Omit it and the API decides: a fast plain fetch first, and a browser instead when the plain fetch comes back blocked, as a challenge wall, or as an empty JavaScript app shell — learned per site, so a site that needs a browser is rendered straight away from then on. `render=true` always uses a browser, `render=false` never does; any wait option asks for a browser by itself. The response says what was used in `render` and why in `render_reason`.","schema":{"type":"boolean"}},{"name":"location","in":"query","required":false,"description":"2-letter country code for residential-proxy geo-targeting.","schema":{"type":"string","enum":["ad","ae","af","ag","al","am","ao","ar","at","au","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bn","bo","br","bs","bt","bw","by","bz","ca","cf","cg","ch","cl","cm","cn","co","cr","cu","cv","cz","de","dj","dk","dm","do","dz","ec","ee","eg","er","es","et","fi","fj","fm","fr","ga","gb","gd","ge","gh","gm","gn","gq","gr","gt","gw","hk","hn","hr","ht","hu","id","ie","il","in","iq","ir","is","it","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","md","me","mg","mk","ml","mm","mn","mr","mt","mu","mv","mw","mx","my","mz","na","ne","ng","ni","nl","no","np","nr","nz","om","pa","pe","pg","ph","pk","pl","pt","pw","py","qa","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","si","sk","sl","sm","sn","so","sr","ss","st","sv","sy","td","tg","th","tj","tl","tm","tn","to","tr","tt","tv","tw","tz","ua","ug","us","uy","uz","vc","ve","vn","vu","ws","ye","za","zm","zw"],"example":"de"}},{"name":"wait_for","in":"query","required":false,"description":"When to capture the page (asks for a browser render by itself). One of `stable` (default — capture once the DOM stops changing), `domcontentloaded` (capture immediately), `networkidle` (wait for the network to go quiet), or **any CSS selector**, which waits for that element to become VISIBLE and then settles. `settle_ms` caps DOM settling; selector waits use the remaining render budget. Tip: on pages that update continuously (live scores, tickers, polling widgets) prefer a selector or `stable` — such pages never go network-quiet, so `networkidle` waits its 8s ceiling and then settles on the DOM, which only slows the response down.","schema":{"type":"string","default":"stable","example":"#results"}},{"name":"wait_min_ms","in":"query","required":false,"description":"Minimum delay after navigation, before scrolling or checking readiness. Useful for discovering content absent from the first capture. Requires a browser.","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}},{"name":"wait_state","in":"query","required":false,"description":"Condition for a CSS selector in wait_for: visible; nonempty (visible text, ignoring common loading placeholders); hidden (all matches hidden or absent); stable (visible text and match count unchanged for 750ms). Conditional wait_rules retain visible semantics. No condition guarantees a complete page.","schema":{"type":"string","enum":["visible","nonempty","hidden","stable"],"default":"visible"}},{"name":"scroll_steps","in":"query","required":false,"description":"Scroll down this many times before the readiness check, pausing between steps. Requires a browser. Bounded discovery for lazy content, not exhaustive collection of infinite or virtualized lists.","schema":{"type":"integer","minimum":0,"maximum":10,"default":0}},{"name":"settle_ms","in":"query","required":false,"description":"Ceiling on the settle wait — **not** a fixed delay. Settling watches the page for DOM changes and captures once nothing has changed for 500ms; every change restarts that 500ms window. A page that goes quiet after 900ms returns after 900ms. `settle_ms` only caps how long that can take: reaching it means the page never stopped changing, and it is captured as-is. Applies to `wait_for=stable` and to selector waits (which settle after the element appears), and after a networkidle timeout. Ignored for `domcontentloaded`. Use `wait_min_ms` for a minimum delay or `scroll_steps` to trigger lazy sections; lower it to cap the worst case on pages that never fully stop.","schema":{"type":"integer","minimum":0,"maximum":25000,"default":5000,"example":12000}},{"name":"wait_rules","in":"query","required":false,"description":"Conditional waits (a browser render, like `wait_for`). Each `if` selector is probed in list order for up to `detect_ms`; the first one that is VISIBLE wins, and its `then` replaces `wait_for` for this request. Nothing matching falls back to `wait_for`. Use this when a page has more than one possible layout — a consent gate, an interstitial, or an A/B variant — so one request handles all of them. On a GET, pass it as a JSON string.","schema":{"type":"array","maxItems":10,"items":{"type":"object","properties":{"if":{"type":"string","description":"CSS selector to probe for"},"then":{"type":"string","description":"What to wait for when it matches. Empty means capture immediately."}},"required":["if"]}}},{"name":"detect_ms","in":"query","required":false,"description":"How long to probe `wait_rules` guards before falling back to `wait_for`.","schema":{"type":"integer","minimum":0,"maximum":25000,"default":800,"example":800}},{"name":"max_age","in":"query","required":false,"description":"Opt-in response cache: accept a previously fetched copy of the same url/render/location and wait settings up to this many seconds old. Cache hits return in milliseconds (the response then carries `cached: true`) instead of re-fetching. 0 (default) always fetches fresh. Recommended when polling the same URLs on a fixed interval.","schema":{"type":"integer","minimum":0,"maximum":300,"default":0,"example":60}},{"name":"template","in":"query","required":false,"description":"Parse the page with a named template and return structured JSON (`response_format: \"json\"`). Takes a reference, `handle/slug`; a bare slug names one of your own templates. Pick one from the Templates table below, or build your own in the editor (editor.unblockingapi.com). The template also supplies the fetch settings it needs — which may include a browser render. Omit it and you get plain HTML: nothing is ever applied to your request unless you name it. Add `@3` to pin a version (`someone/their-template@3`) and keep getting exactly what that version returned, whatever its author changes next.","schema":{"type":"string","example":"kjellberg/google-search"}}]},"post":{"tags":["Unblock"],"summary":"Fetch a URL","description":"Returns the page HTML, or structured JSON when you name a template with `template` (see below). Both GET and POST are supported; POST takes a JSON body.\n\n## Templates\n\nPass `template=<name>` to get structured JSON (`response_format: \"json\"`)\ninstead of HTML, with `api_name` naming the template used. The template\nsupplies the fetch settings its parser needs, which may include a browser\nrender — billed like any render request.\n\nNothing is applied automatically: without `template` you always get the\nraw page. An unknown template, or one that is not yours and not public,\nis a `404`.\n\n### Pinning a version\n\nEvery save its author makes takes a template to the next version, and\n`template_version` in the response says which one answered. Pin one with\n`template=someone/their-template@3` and you keep getting exactly what\nversion 3 returned, however much its author edits afterwards — which is\nwhat lets you build against a shape and leave it alone. Unpinned, you\nalways follow the latest. A version above the latest is a `404`; a\ntemplate its author unpublishes stops serving its old versions too.\n\nIf a parser fails (the site changed its markup), you get the raw HTML\nback with `parse_error: true` rather than an error.\n\nAnyone can build a template in the editor (editor.unblockingapi.com) and publish it here.\n\n| Template | Built for | Fetched | Source | Returns |\n|---|---|---|---|---|\n| `kjellberg/ahrefs-website-authority-checker` | ahrefs.com/website-authority-checker | rendered, from ES | Community | Check the “authority” of your domain (as measured by Ahrefs). Returns all the statistics from the Ahrefs free tool. |\n| `kjellberg/avanza-borsen-idag` | avanza.se/borsen-idag.html | rendered | Community |  |\n| `kjellberg/bing` | bing.com/search | plain HTTP | Community | Parse search results from Bing |\n| `kjellberg/eniro-foretag` | eniro.se/*/f%C3%B6retag | plain HTTP, from SE | Community |  |\n| `kjellberg/google-search` | google.com/search | rendered | Community |  |\n| `kjellberg/hemnet-landing-page` | hemnet.se | rendered | Community | List latest properties and top ranked properties in different categories from Hemnet.se's landing page. |\n| `kjellberg/hetzner-auction` | hetzner.com/sb | rendered, from DE | Community | List available servers in the Hetzner auction |\n| `kjellberg/hi-homes-search` | hihomes.es/property-for-sale | plain HTTP | Community | Search properties in Costa del Sol |\n| `kjellberg/idealista-search` | idealista.com/*/** | rendered, from ES | Community | Get all listings from a search page on Idealista.com. |\n| `kjellberg/marbella-living-property` | marbellaliving.com | plain HTTP | Community | Get data from a property listing on Marbella Living's website. |\n| `kjellberg/marbella-living-search` | marbellaliving.com/search.php | plain HTTP, from ES | Community | API for Marbella Living property listings. Search with any parameter. |\n| `kjellberg/mempool-space-block-view` | mempool.space/block/** | rendered | Community |  |\n| `kjellberg/reddit-post` | reddit.com/r/** | rendered | Community | Parses any public Reddit post. Just paste the link and it will return JSON. Full post + first level comments.  |\n| `kjellberg/serneholt-estates-search` | serneholtestate.com/properties/** | plain HTTP, from ES | Community |  |\n| `kjellberg/sigma-world-category` | sigma.world/latest-news/** | plain HTTP | Community | Receives a list of article info and urls. |\n","responses":{"200":{"description":"Success — the target returned a 2xx. Body carries the fetched content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Out of credits (or the account is still provisioning). Buy a credit pack or subscribe at https://unblockingapi.com/billing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Target returned 404. Treated as a successful result (status is \"succeeded\"), not a failure. A 404 with only an `error` field instead means `template` named no template you can use.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"422":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests in flight for this API key — over your plan's concurrency limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The target site failed — any non-2xx/404 status, a block, a captcha wall, or a render failure. The target's real status is in `http_response_code` and the reason in `error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"503":{"description":"Service temporarily unavailable — our proxy pool is exhausted or the render backend is unreachable/saturated. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}},"504":{"description":"Timed out waiting for the target or the render backend.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockResponse"}}}}},"operationId":"unblockPost","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","example":"https://example.com","description":"URL to fetch. Must be http(s) and not point at a media/binary file."},"render":{"type":"boolean","description":"Whether to render with a real browser (executes JavaScript). Omit it and the API decides: a fast plain fetch first, and a browser instead when the plain fetch comes back blocked, as a challenge wall, or as an empty JavaScript app shell — learned per site, so a site that needs a browser is rendered straight away from then on. `render=true` always uses a browser, `render=false` never does; any wait option asks for a browser by itself. The response says what was used in `render` and why in `render_reason`."},"location":{"type":"string","enum":["ad","ae","af","ag","al","am","ao","ar","at","au","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bn","bo","br","bs","bt","bw","by","bz","ca","cf","cg","ch","cl","cm","cn","co","cr","cu","cv","cz","de","dj","dk","dm","do","dz","ec","ee","eg","er","es","et","fi","fj","fm","fr","ga","gb","gd","ge","gh","gm","gn","gq","gr","gt","gw","hk","hn","hr","ht","hu","id","ie","il","in","iq","ir","is","it","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","md","me","mg","mk","ml","mm","mn","mr","mt","mu","mv","mw","mx","my","mz","na","ne","ng","ni","nl","no","np","nr","nz","om","pa","pe","pg","ph","pk","pl","pt","pw","py","qa","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","si","sk","sl","sm","sn","so","sr","ss","st","sv","sy","td","tg","th","tj","tl","tm","tn","to","tr","tt","tv","tw","tz","ua","ug","us","uy","uz","vc","ve","vn","vu","ws","ye","za","zm","zw"],"example":"de","description":"2-letter country code for residential-proxy geo-targeting."},"wait_for":{"type":"string","default":"stable","example":"#results","description":"When to capture the page (asks for a browser render by itself). One of `stable` (default — capture once the DOM stops changing), `domcontentloaded` (capture immediately), `networkidle` (wait for the network to go quiet), or **any CSS selector**, which waits for that element to become VISIBLE and then settles. `settle_ms` caps DOM settling; selector waits use the remaining render budget. Tip: on pages that update continuously (live scores, tickers, polling widgets) prefer a selector or `stable` — such pages never go network-quiet, so `networkidle` waits its 8s ceiling and then settles on the DOM, which only slows the response down."},"wait_min_ms":{"type":"integer","minimum":0,"maximum":10000,"default":0,"description":"Minimum delay after navigation, before scrolling or checking readiness. Useful for discovering content absent from the first capture. Requires a browser."},"wait_state":{"type":"string","enum":["visible","nonempty","hidden","stable"],"default":"visible","description":"Condition for a CSS selector in wait_for: visible; nonempty (visible text, ignoring common loading placeholders); hidden (all matches hidden or absent); stable (visible text and match count unchanged for 750ms). Conditional wait_rules retain visible semantics. No condition guarantees a complete page."},"scroll_steps":{"type":"integer","minimum":0,"maximum":10,"default":0,"description":"Scroll down this many times before the readiness check, pausing between steps. Requires a browser. Bounded discovery for lazy content, not exhaustive collection of infinite or virtualized lists."},"settle_ms":{"type":"integer","minimum":0,"maximum":25000,"default":5000,"example":12000,"description":"Ceiling on the settle wait — **not** a fixed delay. Settling watches the page for DOM changes and captures once nothing has changed for 500ms; every change restarts that 500ms window. A page that goes quiet after 900ms returns after 900ms. `settle_ms` only caps how long that can take: reaching it means the page never stopped changing, and it is captured as-is. Applies to `wait_for=stable` and to selector waits (which settle after the element appears), and after a networkidle timeout. Ignored for `domcontentloaded`. Use `wait_min_ms` for a minimum delay or `scroll_steps` to trigger lazy sections; lower it to cap the worst case on pages that never fully stop."},"wait_rules":{"type":"array","maxItems":10,"items":{"type":"object","properties":{"if":{"type":"string","description":"CSS selector to probe for"},"then":{"type":"string","description":"What to wait for when it matches. Empty means capture immediately."}},"required":["if"]},"description":"Conditional waits (a browser render, like `wait_for`). Each `if` selector is probed in list order for up to `detect_ms`; the first one that is VISIBLE wins, and its `then` replaces `wait_for` for this request. Nothing matching falls back to `wait_for`. Use this when a page has more than one possible layout — a consent gate, an interstitial, or an A/B variant — so one request handles all of them. On a GET, pass it as a JSON string."},"detect_ms":{"type":"integer","minimum":0,"maximum":25000,"default":800,"example":800,"description":"How long to probe `wait_rules` guards before falling back to `wait_for`."},"max_age":{"type":"integer","minimum":0,"maximum":300,"default":0,"example":60,"description":"Opt-in response cache: accept a previously fetched copy of the same url/render/location and wait settings up to this many seconds old. Cache hits return in milliseconds (the response then carries `cached: true`) instead of re-fetching. 0 (default) always fetches fresh. Recommended when polling the same URLs on a fixed interval."},"template":{"type":"string","example":"kjellberg/google-search","description":"Parse the page with a named template and return structured JSON (`response_format: \"json\"`). Takes a reference, `handle/slug`; a bare slug names one of your own templates. Pick one from the Templates table below, or build your own in the editor (editor.unblockingapi.com). The template also supplies the fetch settings it needs — which may include a browser render. Omit it and you get plain HTML: nothing is ever applied to your request unless you name it. Add `@3` to pin a version (`someone/their-template@3`) and keep getting exactly what that version returned, whatever its author changes next."}},"required":["url"]}}}}}},"/templates.json":{"get":{"tags":["Templates"],"summary":"List published templates","operationId":"listTemplates","description":"The public template catalogue, most used first, with the categories. No API key needed and no credit charged. Pass a template's `reference` as `/unblock`'s `template` parameter to use it. The filters apply to the whole catalogue before the page is cut, and `total` counts every match.","security":[],"parameters":[{"name":"url","in":"query","required":false,"schema":{"type":"string","format":"uri","example":"https://www.google.com/search?q=coffee"},"description":"Only the templates built for this page (its host, path and required query parameters), the most specific pattern first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":500,"example":"property"},"description":"Text search over name, description, slug, reference, host and the author's handle (case-insensitive). `@handle` lists one author's templates; a URL works like `url`."},{"name":"category","in":"query","required":false,"schema":{"type":"string","example":"real-estate"},"description":"Only templates in this category (its slug)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"How many templates to return per page."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Which page of `limit` templates to return, from 1."}],"responses":{"200":{"description":"The catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateCatalogue"}}}}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Api-Key"},"BearerAuth":{"type":"http","scheme":"bearer"},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"key","description":"API key as a query parameter (?key=…)"}},"schemas":{"UnblockResponse":{"type":"object","properties":{"job_id":{"type":"string","description":"Unique id for this request."},"url":{"type":"string"},"status":{"type":"string","enum":["succeeded","failed"],"description":"\"succeeded\" for 2xx and 404 targets; \"failed\" otherwise."},"http_response_code":{"type":"integer","example":200,"description":"The target's actual status code. On an HTTP 500 response this holds the real upstream code (e.g. 403, 429) that caused the failure."},"response_time_ms":{"type":"integer"},"wait_timed_out":{"type":"boolean","description":"A requested browser wait reached its limit; delivered HTML may still be useful. A wait_for selector is waited for at most 20 seconds; one that never appears is reported here, and the request still succeeds and costs 1 credit."},"readiness":{"type":"object","properties":{"status":{"type":"string","enum":["satisfied","timeout","unavailable"]},"reason":{"type":"string"},"waited_ms":{"type":"integer"},"scroll_steps":{"type":"integer"},"verification":{"type":"object","nullable":true,"properties":{"vendor":{"type":"string","enum":["turnstile"]},"status":{"type":"string","enum":["solved","interactive","pending"]},"waited_ms":{"type":"integer"}},"description":"A visible site verification widget (Cloudflare Turnstile) on the page. \"interactive\": it shows its checkbox and needs a click, so a longer wait will not help. \"pending\": still verifying after 15 seconds."}},"description":"Browser wait outcome, when supported by the worker. Satisfied describes the chosen condition, not completeness of the page."},"render":{"type":"boolean","description":"Whether a browser rendered the page."},"render_reason":{"type":"string","nullable":true,"description":"Why: plain | replay (a plain fetch carrying the session a browser established for this site) | fallback:challenge | fallback:blocked | fallback:shell | fallback:replay | site:<why> | wait | template | requested."},"location":{"type":"string","nullable":true},"response_format":{"type":"string","enum":["html","json"]},"api_name":{"type":"string","description":"The template used, when one was requested."},"template_version":{"type":"integer","description":"Which version of that template answered — the one you pinned, or its latest. This is the number to pin to."},"error":{"type":"string","description":"Present only when status is failed."},"response":{"description":"HTML string for html responses; structured JSON for template responses."}}},"TemplateResponse":{"type":"object","description":"Same envelope as UnblockResponse, with response_format=json and a parsed `response`.","properties":{"job_id":{"type":"string"},"url":{"type":"string"},"status":{"type":"string","enum":["succeeded","failed"]},"http_response_code":{"type":"integer"},"response_time_ms":{"type":"integer"},"render":{"type":"boolean","description":"Whether a browser rendered the page."},"render_reason":{"type":"string","nullable":true,"description":"Why: plain | replay (a plain fetch carrying the session a browser established for this site) | fallback:challenge | fallback:blocked | fallback:shell | fallback:replay | site:<why> | wait | template | requested."},"location":{"type":"string","nullable":true},"response_format":{"type":"string","example":"json"},"api_name":{"type":"string"},"response":{"description":"Structured data parsed from the page (shape depends on the template)."}}},"TemplateCatalogue":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string","example":"search-results"},"name":{"type":"string"},"group":{"type":"string"},"description":{"type":"string"},"templates_count":{"type":"integer"}}}},"templates":{"type":"array","items":{"type":"object","properties":{"reference":{"type":"string","example":"kjellberg/google-search","description":"What to pass as `template` on /unblock."},"api_name":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"username":{"type":"string"},"category":{"type":"string"},"category_label":{"type":"string"},"host":{"type":"string","example":"google.com","description":"The site it was built for."},"path":{"type":"string","example":"/search","description":"Path prefix it was built for. `*` is one segment, `**` any deeper path."},"fields":{"type":"array","items":{"type":"string"},"description":"The fields it returns."},"field_count":{"type":"integer"},"render":{"type":"boolean","nullable":true},"location":{"type":"string","nullable":true},"stars_count":{"type":"integer"},"forks_count":{"type":"integer"},"requests_count":{"type":"integer"},"page_url":{"type":"string"},"sample_url":{"type":"string"},"editor_url":{"type":"string"}}}},"total":{"type":"integer","description":"How many templates match the filters, across all pages."},"page":{"type":"integer","description":"The page returned, from 1."},"limit":{"type":"integer","description":"The page size used."}}},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}