# LangChain (Python): check several quotes on one page

Last updated: 2026-10-12

A LangChain 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.

To check one quote at a time or a batch of links, on the free trial with no payment code, see [LangChain: check a quote before citing it](https://vehcdj664efetfrsolne5umanq.srv.us/docs/examples/langchain).

The same check for other frameworks: [LlamaIndex](https://vehcdj664efetfrsolne5umanq.srv.us/examples/llamaindex.md), [OpenAI Agents SDK](https://vehcdj664efetfrsolne5umanq.srv.us/examples/openai-agents.md) and [Claude Agent SDK](https://vehcdj664efetfrsolne5umanq.srv.us/examples/claude-agent-sdk.md).

## Install

Python 3.10 or later.

```sh
pip install "langchain>=1.0" langchain-anthropic "x402[requests,evm]"
export ANTHROPIC_API_KEY=...
export ATTESTPAGE_X402_KEY=0x...
```

Any chat model LangChain supports works; set `MODEL` (for example `openai:gpt-5`) and install its package. `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

```python
"""LangChain agent that checks quotes with POST /v1/verify/quotes, paying per call with x402."""
import os
import sys

from eth_account import Account
from langchain.agents import create_agent
from langchain.tools import tool
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)


@tool
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."""
    res = session.post(f"{ORIGIN}/v1/verify/quotes", json={"url": url, "quotes": quotes}, timeout=60)
    return res.json()


agent = create_agent(
    model=os.environ.get("MODEL", "anthropic:claude-sonnet-5-5"),
    tools=[verify_quotes],
    system_prompt=(
        "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 __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"?'
    )
    result = agent.invoke({"messages": [{"role": "user", "content": question}]})
    print(result["messages"][-1].content)
```

```sh
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. A request the service refuses (bad URL, empty quote) is refused before payment and not charged.

## What comes back

- `results[i].match`: `exact`, `fuzzy` or `none`, in the order of `quotes`. Read `page.content_kind` first: `none` on a `bot_wall` or `js_shell` page means the page could not be read.
- `receipt`: signed evidence of what the page said and when our fetcher saw it, as a JWS. `POST /v1/receipt/verify` checks it for free, or check it offline with [`verify-receipt.mjs`](https://vehcdj664efetfrsolne5umanq.srv.us/docs/verify-offline). A receipt records what was on the page at that time, not whether a statement on it is correct.
- Try the answer shape first with the free sample: `GET https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/quotes`.

## Terms

Pay per call, no account. See [Payments](https://vehcdj664efetfrsolne5umanq.srv.us/docs/payments), [Limits](https://vehcdj664efetfrsolne5umanq.srv.us/docs/limits) and the [Terms](https://vehcdj664efetfrsolne5umanq.srv.us/terms).
