Fetch a page
Last updated: 2026-10-12
POST /v1/fetch fetches one URL (or up to 10 with urls) and tells you what came back: a page.content_kind verdict, HTTP status, final URL after redirects, title, hashes, injection flags and, if you ask, up to 20,000 characters of clean text. Price: US$0.002 per URL: one url is US$0.002, and urls costs US$0.002 times the number of URLs.
Use it when you need to know whether a URL gave you real content, a bot challenge, a JavaScript shell, a paywall or an error, with a receipt that records it. It is also how you notarize a web page: the signed receipt records what the page said and when.
Request
{ "url": "https://www.iana.org/help/example-domains", "return_text": true }
| Field | Required | Meaning |
|---|---|---|
url | url or urls | http or https URL, at most 2,048 characters |
urls | url or urls | instead of url: a list of 1 to 10 distinct URLs, each priced as one fetch; see Several pages in one call |
return_text | no | also return up to 20,000 characters of clean text (per page); default false |
Response
From the free sample (GET /v1/sample/fetch), shortened:
{
"page": {
"requested_url": "https://s2h6qt73jtzlgbgnnfacln2poq.srv.us/v1/sample/page",
"final_url": "https://s2h6qt73jtzlgbgnnfacln2poq.srv.us/v1/sample/page",
"http_status": 200,
"content_type": "text/html",
"content_kind": "real",
"signals": ["status_200"],
"title": "Regional climate report 2025 (demo page)",
"redirects": [],
"content_sha256": "0e429607…",
"raw_sha256": "179b9ac4…",
"retrieved_at": "2026-10-09T14:19:34.909Z",
"bytes": 847,
"truncated": false
},
"text": "Regional climate report 2025\n\nThis is a demo page…",
"text_chars": 636,
"text_truncated": false,
"injection_flags": [],
"advice": "The page loaded and looks like real content.",
"receipt": "eyJhbGciOiJFZERTQSIs…",
"tier": "paid",
"rail": "x402",
"network": "eip155:8453"
}
- Receipts are signed by
isshttps://still-rapids-9yt7.here.now (keys at /.well-known/jwks.json), not by the origin you called. Check one free withPOST /v1/receipt/verify(docs). page.content_kindandpage.signalsare explained in How it works.adviceis one plain sentence about the verdict.content_sha256hashes the full extracted text, not the 20,000-character copy.raw_sha256hashes the bytes as received.content_sha256is null when no body was read.injection_flagslists prompt-injection patterns found in the text, such asinstruction_overrideorhidden_instructions. They are flags, not a verdict: an empty list means none of our patterns matched.textis null unless you setreturn_text.
Several pages in one call
Send urls instead of url to fetch up to 10 pages in one paid call:
{ "urls": ["https://www.iana.org/help/example-domains", "https://www.iana.org/domains/reserved"], "return_text": true }
- The price is US$0.002 times the number of URLs, on every rail: the 402 offer (x402
PAYMENT-REQUIRED, the L402 invoice) is made for that body, so send the same body when you pay. A credit key is charged the sats price times the count. - The answer is
{ "results": [...], "tier", "rail", "network" }.resultshas one entry per URL, in the order sent:{ "url", "page", "text", "text_chars", "text_truncated", "injection_flags", "advice", "receipt" }, each as for oneurl. - Each page has its own receipt, the same size as a one-page receipt, so Recheck and
POST /v1/receipt/verifytake each one alone. Each also signsresult.batch: { "index", "count" }(its place in the call) and therequest_sha256of the whole request. - Each URL may appear once; a repeat is refused with 400 before payment. Send
urlorurls, not both. - As for one page, a bad URL, a blocked address or a host name that does not resolve is refused before payment (with
details.fieldsuch asurls[2]). If any page turns out to be disallowed by robots.txt or rate limited after payment, the whole call answers with that error and is not charged. - A free trial call covers at most 5 URLs; a larger one gets the normal 402 offer,
details.reasontrial_too_large.
An application/pdf page is read too, within the same 2 MB and 10-second limits. Only its text layer is read, with no OCR, so a scanned PDF comes back as empty with the signal pdf_no_text_layer.
signalsincludespdf.titleis the PDF's own title, if it has one.texthas the pages in order, separated by a form feed (\f).- Only text inside each page's box is read, as a reader sees it. Text drawn outside the page is not in
text. page.pdfgivespage_count,pages_readandtruncated. Very long PDFs stop at a page or character cap, with the signalpdf_truncated. The receipt signs these as well.- A PDF we could not read is
unsupported_typewith a signal saying why:pdf_encrypted,pdf_invalid,pdf_over_budget,pdf_timeoutorpdf_out_of_memory. It is charged like any other page we cannot read. - When too many PDFs are waiting to be read, the call gets 503
over_capacity(details.reasonpdf_queue_full) withRetry-After. It is not charged.
Only the full service reads PDFs: an edge server answers 501 not_on_edge (details.reason pdf) for one, not charged. Limits are in Limits.
Later: has it changed?
Keep the receipt. Recheck (POST /v1/recheck, US$0.003) takes it later, fetches the page again and says unchanged, changed, gone or unreadable, with a signed receipt naming both hashes.
Charging
A bad URL, a blocked address or a host name that does not resolve is refused before payment and not charged. Results about the page itself, including 404s and bot walls, are charged: that is the answer you paid for. A fetch that read no page (a timeout, a failed connection, an undecodable body, too many redirects, or a redirect we refuse) answers 502 upstream_unreachable with details.reason, and is not charged. In a batch the call is charged once, when at least one URL read a page; if none did, it is 502 and not charged. See Payments.