AttestPage · Docs · Pricing · OpenAPI · llms.txt

Pydantic AI: check several quotes on one page

Last updated: 2026-10-13

A Pydantic AI agent in Python that checks up to 20 quotes from one web page in one call to POST /v1/verify/quotes before it cites them. Price: US$0.02 per call, for 1 to 20 quotes. Each quote comes back exact, fuzzy or none, with offsets and context, plus the page's verdict and an Ed25519-signed receipt. Payments are in USDC with x402 v2 on Base mainnet (real USDC).

The tool calls the route over HTTP and pays with the x402 Python package.

The same check for other frameworks: LangChain, LlamaIndex, OpenAI Agents SDK, Claude Agent SDK, Vercel AI SDK, CrewAI and Mastra.

Install

Python 3.10 or later.

pip install "pydantic-ai-slim[anthropic]" "x402[requests,evm]"
export ANTHROPIC_API_KEY=...
export ATTESTPAGE_X402_KEY=0x...

Any model Pydantic AI supports works; set MODEL (for example openai:gpt-5) and install its extra. ATTESTPAGE_X402_KEY is the private key (0x and 64 hex digits) of a wallet holding a little USDC. The key stays in your process.

agent_http.py

"""Pydantic AI agent that checks quotes with POST /v1/verify/quotes, paying per call with x402."""
import os
import sys

from eth_account import Account
from pydantic_ai import Agent
from x402 import x402ClientSync
from x402.http.clients import x402_requests
from x402.mechanisms.evm.exact import ExactEvmScheme
from x402.mechanisms.evm.signers import EthAccountSigner

ORIGIN = os.environ.get("ATTESTPAGE_URL", "https://vehcdj664efetfrsolne5umanq.srv.us").rstrip("/")
MAX_UNITS = 20000  # US$0.02 in USDC (6 decimals): the most one call may cost

client = x402ClientSync()
client.register("eip155:8453", ExactEvmScheme(signer=EthAccountSigner(Account.from_key(os.environ["ATTESTPAGE_X402_KEY"]))))
client.register_policy(lambda _version, reqs: [
    r for r in reqs if r.network == "eip155:8453" and int(r.get_amount()) <= MAX_UNITS
])
session = x402_requests(client)

agent = Agent(
    os.environ.get("MODEL", "anthropic:claude-sonnet-5-5"),
    instructions=(
        "Before you quote a web page, call verify_quotes once with every quote you plan to use from it. "
        "Cite a quote only when its match is exact or fuzzy and page.content_kind is real. "
        "If the tool returns an error, say what it was and stop."
    ),
)


@agent.tool_plain
def verify_quotes(url: str, quotes: list[str]) -> dict:
    """Use before quoting one web page several times: checks 1 to 20 quotes against the page at url.
    Returns results[i].match (exact, fuzzy or none), page.content_kind and a signed receipt. US$0.02 per call."""
    try:
        res = session.post(f"{ORIGIN}/v1/verify/quotes", json={"url": url, "quotes": quotes}, timeout=60)
    except Exception as e:  # the policy above refused every offer, or the network failed
        return {"error": f"{e}. This recipe pays at most US$0.02 in USDC on eip155:8453."}
    if res.status_code == 402:  # not paid: no offer was acceptable
        return {"error": "payment required", "payment_required": res.headers.get("PAYMENT-REQUIRED")}
    return res.json()


if __name__ == "__main__":
    question = " ".join(sys.argv[1:]) or (
        'Does https://www.iana.org/help/example-domains say "These domains may be used as '
        'illustrative examples in documents" and "without prior coordination with us"?'
    )
    print(agent.run_sync(question).output)
python agent_http.py   # pays US$0.02 per call in USDC

The first request gets a 402 with the price in the PAYMENT-REQUIRED header; the x402 session signs the payment and sends it again. The policy keeps only offers on Base (eip155:8453) of at most US$0.02, so a higher price or another network is refused before anything is signed. The tool returns that refusal, or a 402 that was not paid, to the agent as an error instead of raising, so the agent can report it and stop. A request the service refuses (bad URL, empty quote) is refused before payment and not charged.

What comes back

Terms

Pay per call, no account. See Payments, Limits and the Terms.