AttestPage · Docs · Pricing · OpenAPI · llms.txt

How to check every quote in a draft before publishing, step by step with curl

Last updated: 2026-10-13

To check every quote in a finished answer or report before it goes out, send the whole text to POST /v1/verify/document (US$0.10 per part of up to 10 pairs). AttestPage finds each quote and the link it points to, fetches each live page, and answers exact, fuzzy or none for every pair, with the verdict on each page and one signed receipt for the whole part.

This guide runs the check with curl and jq against https://vehcdj664efetfrsolne5umanq.srv.us. For checking a single quote, see How to check a quote an LLM cites.

What the check does

Price

US$0.10 per part of up to 10 pairs, paid in USDC with x402 v2 on Base mainnet (real USDC). A document with 10 quotes or fewer is one part. No account, key or sign-up. A request that fails validation gets 400 before payment and is never charged. All prices: pricing.json.

1. Preview the pairs for free

The preview is free and changes nothing. It lists every pair it found, what was skipped and why, the number of parts and the exact price. Put the draft in a file:

cat > document.json <<'EOF'
{ "document": "WHO says \"Air pollution kills an estimated seven million people every year\" ([WHO](https://www.who.int/health-topics/air-pollution)).", "format": "markdown" }
EOF
curl -s -X POST https://vehcdj664efetfrsolne5umanq.srv.us/v1/verify/document/preview -H 'content-type: application/json' -d @document.json \
  | jq '{pairs_total, parts, price: .price.usd_total, skipped_counts, pairs: [.pairs[] | {quote, url}]}'
{
  "pairs_total": 1,
  "parts": 1,
  "price": "0.10",
  "skipped_counts": {},
  "pairs": [
    {
      "quote": "Air pollution kills an estimated seven million people every year",
      "url": "https://www.who.int/health-topics/air-pollution"
    }
  ]
}

Check that each quote is the one you mean and that each link is the source you cited. A quote in skipped with no_url has no link next to it, so it is not checked.

2. Read the price from the 402 offer

A request with a valid body gets the payment offer without being charged. The PAYMENT-REQUIRED header is base64 JSON:

curl -si -X POST https://vehcdj664efetfrsolne5umanq.srv.us/v1/verify/document -H 'content-type: application/json' -d @document.json \
  | grep -i '^payment-required:' | cut -d' ' -f2 | tr -d '\r' | base64 -d \
  | jq '.accepts[0] | {scheme, network, amount, payTo}'

amount is in USDC base units (6 decimals), so 100000 is US$0.10.

3. Check the part

Put the draft and the part number in a file. Part 0 is the first 10 pairs:

cat > body.json <<'EOF'
{ "document": "WHO says \"Air pollution kills an estimated seven million people every year\" ([WHO](https://www.who.int/health-topics/air-pollution)).", "format": "markdown", "part": 0 }
EOF

Pay with any x402 v2 client: it reads the offer from step 2, signs it and sends the same request again with a PAYMENT-SIGNATURE header. One x402 payment step by step shows this with plain fetch, and the MCP server does it for you. To check a longer draft, set "part" to 1 (then 2 and so on) in body.json; the preview gives the number of parts. Save the paid answer as answer.json for the steps below.

4. Read the answer

Start with summary, then go through results. Each result carries the quote, its url, content_kind, match, score and context:

jq '.summary' answer.json
jq '.results[] | {quote, url, content_kind, match, score}' answer.json
content_kindmatchWhat it means
realexactThe quoted words are on the page.
realfuzzyA close match. Compare context with the quote: a word may have changed.
realnoneThe quote is not on the page as fetched. Fix the quote or the link before you publish.
bot_wall, js_shell, paywall, http_erroranyThe page could not be read. The quote is unchecked, not false.

Each result also gives doc_start and doc_end, the position of the quote in your draft, so you can find it. A quote that appears more than once is checked once and listed with doc_spans.

5. Keep the receipt

The receipt field is a compact JWS. Keep it with the draft. Check it with the free verify route:

jq '{receipt}' answer.json \
  | curl -s -X POST https://vehcdj664efetfrsolne5umanq.srv.us/v1/receipt/verify -H 'content-type: application/json' -d @- | jq .valid

Or check it offline with our single-file checker: Verify receipts offline.

With MCP

The same check is the MCP tool attestpage_verify_document, with the body from step 3 as its arguments. To use it from an MCP client with nothing to install, add the remote endpoint:

{
  "mcpServers": {
    "attestpage": { "type": "http", "url": "https://vehcdj664efetfrsolne5umanq.srv.us/mcp" }
  }
}

Or run the local server, which pays from your own wallet key within limits you set: MCP server.

One call to the remote endpoint with curl. _meta["attestpage/trial"] set to false asks for the payment offer rather than a trial call, so nothing is charged:

curl -s -X POST https://vehcdj664efetfrsolne5umanq.srv.us/mcp -H 'content-type: application/json' -d @- <<'EOF' \
  | jq '.result.structuredContent.accepts[0] | {scheme, network, amount}'
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
  "params": { "name": "attestpage_verify_document",
    "arguments": { "document": "WHO says \"Air pollution kills an estimated seven million people every year\" ([WHO](https://www.who.int/health-topics/air-pollution)).", "format": "markdown", "part": 0 },
    "_meta": { "attestpage/trial": false } } }
EOF
{
  "scheme": "exact",
  "network": "eip155:8453",
  "amount": "100000"
}

The result has isError: true and the x402 payment requirements in structuredContent, with the same amount as step 2. Sign one of accepts, put the payload in _meta["x402/payment"] and call again: structuredContent is then the same JSON as answer.json, and _meta["x402/payment-response"] holds the settlement.

Questions

How much does a check cost?

US$0.10 per part of up to 10 pairs. A draft with 23 quotes is 3 parts, so 3 calls. The preview in step 1 shows the exact count and total before you pay.

Is a part charged if a page will not load?

Yes, when the part is checked. A page that returns a 404, a bot wall or a timeout is charged, because that result is what the check finds; content_kind says so. A request that fails validation, a document with no quotes that have links, and a part where no URL resolves are never charged.

Does exact mean the claim in the draft is right?

No. It means those words were on the page as fetched at that time. Whether the page itself is right is a separate question.

What if the draft is longer than 60,000 bytes?

Split it and check each piece as its own document. Up to 100 pairs are checked per document, in 10 parts.