x402 Whitepaper: Agent Payment Verification

Published: Updated: Author: Ontario Protocol

Ontario Protocol is pre-payment verification and discovery infrastructure for x402-paid endpoints. This document describes how endpoint metadata, HTTP 402 challenges, signed readiness reports, can-pay policy, service discovery, and settlement evidence fit together before an agent spends.

Fastest path from architecture to a real signal

If you are evaluating whether an agent should trust or pay an x402 endpoint, do not start with a payment. Run the free readiness verifier, run the can-pay policy check, then move to the smallest paid proof only when your policy returns allow.

1. The shape of the problem

Autonomous AI agents need three things that classic SaaS does not give them:

  1. Per-call settlement. Agents transact in micropayments — cents and fractions of cents — and only when they actually need a capability. Subscriptions and API keys are unfit for purpose.
  2. Auto-discovery. Agents do not read landing pages. They consume manifests. Anything an agent needs to know about a service must be machine-readable and reachable in one HTTP round-trip.
  3. Verifiable trust. When an agent decides whether to trust another agent, it cannot rely on hand-waved testimonials. It needs a structured signal it can audit on-chain.

x402 covers (1) and (2). EAS covers (3). Ontario Protocol stitches them together and operates the marketplace on top.

2. Stack overview

+--------------------------------------------------------------------+
|  Agents (LangChain, CrewAI, Anthropic MCP clients, OpenAI, custom) |
+----------------+---------------------------------------------------+
                 |  HTTP (x402)
                 v
+--------------------------------------------------------------------+
|  Ontario Protocol — Flask app                                       |
|  - x402_server.py        (HTTP 402 middleware)                      |
|  - agent_discovery.py    (.well-known + /discover + /listings)      |
|  - agent_trust_scanner.py(paid trust scan)                          |
|  - reputation_eas.py     (EAS attestations on Base)                 |
|  - proxy_facilitator.py  (1.5% take-rate wrapper)                   |
|  - take_rate_ledger.py   (append-only SQLite)                       |
|  - treasury.py           (public dashboard)                         |
+----+----------------------+----------------------+-----------------+
     |                      |                      |
     v                      v                      v
Coinbase Facilitator   EAS contract on Base   Base RPC
(verify + settle)      (0x4200...0021)        (basescan.org)
     |
     v
USDC ERC-20 (0x8335...0913)

3. The x402 flow

Every paid endpoint follows the canonical x402 dance:

  1. Client makes the call without payment.
  2. Server returns HTTP 402 with a base64-encoded PAYMENT-REQUIRED header. The decoded payload describes the asset, the amount, the network, the receiver, and a nonce.
  3. Client signs an EIP-3009 transferWithAuthorization message and base64-encodes the result into a PAYMENT-SIGNATURE header.
  4. Server forwards the signed payload to a facilitator (Coinbase by default) for verify + settle. On success, the facilitator submits the on-chain transaction; on failure the server returns HTTP 402 again with the failure reason.
  5. Server returns HTTP 200 with the actual response, plus a base64 PAYMENT-RESPONSE header containing {success, transaction, network, payer}.

All of this is implemented in x402_server.py as a Flask decorator. Adding a new paid endpoint is one decorator and one view function.

4. Discovery

Agents discover Ontario through three surfaces, all served as JSON:

URLPurpose
/.well-known/x402.jsonStandardised manifest. The default place an agent looks.
/discoverFlat catalog with filtering. ?category=trust etc.
/listingsContent-negotiated: HTML for humans, JSON for agents.

The same data is also rendered into listings_out/coinbase-bazaar.yaml and listings_out/mcp-server.json for syndication via the Coinbase Bazaar registry and the MCP server registry respectively.

5. Trust scans & reputation

agent_trust_scanner.py performs a deterministic, side-effect-free scan of an agent's surface area:

The trust score is the unweighted percentage of positive signals that fired. It is intentionally simple — there are no hidden weights — so consumers can re-derive the same number from signals alone.

Each scan is recorded as an attestation through reputation_eas.py. When EAS_SIGNER_PRIVATE_KEY and EAS_SCHEMA_UID are configured, the attestation is submitted on-chain to the Base EAS contract at 0x4200000000000000000000000000000000000021; otherwise it is stored in the local SQLite mirror only and labelled onchain: false.

6. Proxy facilitator & take rate

proxy_facilitator.py wraps Coinbase's hosted facilitator. Its verify() is a pure pass-through. Its settle():

  1. Forwards the call to Coinbase, on Base mainnet, settling USDC.
  2. Looks up the resource against agent_discovery to detect whether the listing is first-party or third-party.
  3. Computes a 1.5% (150 bps) take rate on third-party gross.
  4. Writes one append-only row to take_rate_ledger.py regardless of outcome — failures included for audit reconciliation.

treasury.py reads the ledger and exposes it at /treasury (HTML) and /api/treasury/stats (JSON). Provider sweeps are deliberately manual at Tier 3; the ledger surfaces the amount owed to each provider so payouts are auditable.

7. Why USDC on Base

8. Failure modes & mitigations

9. What's next

Source code lives in the same repository as this site. Nothing on this page is hand-typed marketing — every number on the homepage and the treasury page is sourced from the live ledger or live counters.