Mercury · Verifiable Web Fetch
GET /buy/fetch
What it does
VERIFIABLE keyless web-read for autonomous agents. Every result ships a cryptographically SIGNED provenance receipt (EIP-191 over sha256(text)+url+status+time) — the wedge a free scraper structurally CANNOT match: Jina r.jina.ai is free+keyless too, but its bytes are HEARSAY (no proof of what/where/when). MERCURY's `attestation` is ecrecoverable OFFLINE, forever, by you OR any downstream agent you forward the bytes to — proving the content is genuine + untampered (key pinned at /.well-known/mercury-attestation). For RAG, trading and agent-to-agent commerce that need provenance, that is the gap between data and evidence. Beyond that it's the keyless web-read primitive — NO API key, NO signup, NO account, NO monthly plan, the one fetch SKU a fresh agent can onboard to by itself instead of stopping to ask a human for a key. Give a ?url= and get back clean readable page text + title + status. Agent-native extras (opt-in): ?format=markdown for structure-preserving markdown, ?links=1 for an outbound-link graph (crawl frontier), and the headline wedge — STRUCTURED EXTRACT: ?extract=title,price,author,publishedAt returns a clean JSON record { title, price, author, publishedAt }, an LLM-ready row not a wall of text. That is Firecrawl's paid 'JSON mode' (they need an LLM call + an API key for it) done here DETERMINISTICALLY from the page's own JSON-LD/OpenGraph/meta/microdata — keyless, no LLM, $0.003. (?extract=1 still returns the legacy description + wordCount.) The extracted record is folded into the SIGNED attestation too, so a buyer can prove the FIELDS — not just the raw bytes — are exactly what MERCURY resolved. You pay in-band over HTTP 402 (x402, USDC on Base mainnet) — the wedge those tools can't match: they ALL gate behind a human-created API key + a credit-card plan, so an agent can't onboard itself. This one an agent finds in the x402 Bazaar and pays with zero human in the loop. Honest charge-per-ATTEMPT: every call returns a structured result (success OR an ok:false failure with a reason) — never a silent charge-then-500. Follows redirects, SSRF-guarded, 5s timeout, 10MB cap. Pure data, no mint — delivers in prod.
The goal it serves: give an agent provable web content — the bytes PLUS a portable, offline-verifiable proof of what/where/when — so RAG stores, research pipelines and downstream agents can cite evidence, not hearsay.
Schemas & output preview
Input schema — the exact request shape the route validates.
{
"type": "object",
"properties": {
"url": {
"type": "string",
"maxLength": 2048,
"description": "the page to fetch (http/https)"
},
"format": {
"type": "string",
"enum": [
"text",
"markdown"
],
"description": "text (default) or structure-preserving markdown"
},
"links": {
"type": "string",
"enum": [
"0",
"1"
],
"description": "1 = also return the outbound-link graph (crawl frontier)"
},
"extract": {
"type": "string",
"maxLength": 256,
"description": "1 = page description + wordCount; OR a comma-list of field names (e.g. title,price,author,publishedAt) to get a structured JSON record under `extract`"
}
},
"required": [
"url"
],
"additionalProperties": false
}Output schema — the exact response shape the handler returns.
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "true on success; false on an honest failure (still delivered)"
},
"url": {
"type": "string",
"description": "final URL after redirects"
},
"status": {
"type": "integer",
"description": "upstream HTTP status"
},
"title": {
"type": "string",
"description": "page <title> (HTML pages only)"
},
"text": {
"type": "string",
"description": "cleaned, readable page text (or markdown if ?format=markdown)"
},
"format": {
"type": "string",
"enum": [
"markdown"
],
"description": "echoed only when ?format=markdown was requested"
},
"description": {
"type": "string",
"description": "page meta/og description (only when ?extract=1)"
},
"wordCount": {
"type": "integer",
"description": "word count of returned text (only when ?extract=1)"
},
"extract": {
"type": "object",
"description": "STRUCTURED JSON record (only when ?extract=<comma-list of fields>). The Firecrawl-JSON-mode wedge: each requested field resolved from JSON-LD/OpenGraph/meta/microdata, absent fields null. Deterministic, keyless, no LLM call. The signed attestation covers this record too.",
"additionalProperties": {
"type": [
"string",
"number",
"boolean",
"null"
]
}
},
"links": {
"type": "array",
"description": "outbound-link graph, same-origin first (only when ?links=1)",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
},
"contentType": {
"type": "string"
},
"bytes": {
"type": "integer",
"description": "raw body size"
},
"truncated": {
"type": "boolean"
},
"error": {
"type": "string",
"description": "present only when ok:false"
},
"attestation": {
"type": "object",
"description": "EIP-191 provenance receipt: a signature over sha256(text)+url+status+time, verifiable OFFLINE by anyone (key pinned at /.well-known/mercury-attestation). Proves the content is genuine + untampered — the non-commodity edge of a signed-payment seller.",
"properties": {
"keyId": {
"type": "string",
"description": "versioned key id (scheme + signer address)"
},
"alg": {
"type": "string",
"description": "EIP-191-personal_sign"
},
"address": {
"type": "string",
"description": "the signer address; recover() must equal this"
},
"contentHash": {
"type": "string",
"description": "0x… sha256 hex of `text`"
},
"nonce": {
"type": "string"
},
"signedAt": {
"type": "string"
},
"signature": {
"type": "string",
"description": "0x… 65-byte EIP-191 signature"
},
"verify": {
"type": "object",
"description": "the exact signed `message` + a one-line howTo, so verification needs no MERCURY SDK",
"properties": {
"message": {
"type": "string"
},
"howTo": {
"type": "string"
}
}
}
}
}
},
"required": [
"ok",
"url"
],
"additionalProperties": false
}Output preview — a real example response, shown free (you only pay when you call the route).
{
"ok": true,
"url": "https://example.com/",
"status": 200,
"title": "Example Domain",
"format": "markdown",
"text": "Example Domain\n\n# Example Domain\n\nThis domain is for use in documentation examples without needing permission. Avoid use in operations. [Learn more](https://iana.org/domains/example)",
"description": "Example Domain # Example Domain This domain is for use in documentation examples without needing permission.",
"wordCount": 22,
"extract": {
"title": "Example Domain",
"price": null,
"author": null
},
"links": [
{
"url": "https://iana.org/domains/example",
"text": "Learn more"
}
],
"contentType": "text/html; charset=utf-8",
"bytes": 513,
"truncated": false,
"attestation": {
"keyId": "mercury-x402-attestation-v1:0x<signer>",
"alg": "EIP-191-personal_sign",
"address": "0x<signer-from-/.well-known/mercury-attestation>",
"contentHash": "0xc372f751afc12f338f7b3cc8ce610bc548c40338bb80c8e0e0b0c06c707a146c",
"nonce": "0x<16-random-bytes>",
"signedAt": "2026-06-03T00:00:00.000Z",
"signature": "0x<65-byte EIP-191 signature>",
"verify": {
"message": "mercury-x402:fetch-attestation:v1\nurl=https://example.com/\nstatus=200\nsha256=0xc372…\nfetchedAt=2026-06-03T00:00:00.000Z\nnonce=0x…",
"howTo": "EIP-191 ecrecover this message; signer must equal address. Recompute sha256(text)==contentHash."
}
}
}Price ladder — each tier delivers genuinely more work, never the same bytes at a markup.
| Tier | Price | Includes |
|---|---|---|
| fetch | $0.003 | clean page text + signed provenance receipt |
| plus | $0.006 | + markdown structure + outbound-link graph |
| pro | $0.012 | + deterministic structured-extract JSON record |
Pay & call
Your agent calls the route; the 402 challenge carries the exact price ($0.003, USDC on Base mainnet); the x402 client settles via the CDP facilitator and retries. No key, no signup.
import { wrapFetchWithPayment } from "x402-fetch";
const pay = wrapFetchWithPayment(fetch, account); // viem account holding a little USDC on Base
const res = await pay("https://network.mercury-hq.com/buy/fetch?url=https://example.com");
const out = await res.json(); // the result + `attestation` (the signed receipt)Prepaid alternative — the same route accepts an API key:
# Same route, prepaid API-key rail (Bearer mk_live_…) — get a key at https://network.mercury-hq.com/developers
curl -H "Authorization: Bearer mk_live_YOURKEY" "https://network.mercury-hq.com/buy/fetch?url=https://example.com"Verify the receipt
Recover the EIP-191 signature over sha256(content)‖url‖status‖fetchedAt‖nonce and confirm the signer equals the pinned attestation key 0xACB40253BD71Bb9a5d491b2c6EFF755F2A33Fc75 (published at /.well-known/mercury-attestation). No callback to Mercury — the receipt verifies offline, forever. Verification is always free: POST the receipt to /x402/verify or run ecrecover yourself.
| Fact | Value |
|---|---|
| Attestation signer (pinned) | 0xACB40253BD71Bb9a5d491b2c6EFF755F2A33Fc75 |
| Key published at | /.well-known/mercury-attestation |
| Live verifier (free) | /x402/verify |
| Settlement | real USDC on Base mainnet (eip155:8453) via CDP — auditable on BaseScan |
Related
Cited Batch
$0.02Cited Markdown
$0.005Cited Readability
$0.005More: all services · /catalog · the headline web-fetch · agent twin of this page: GET /university/docs/web-fetch?format=md