x402 Marketplace Architecture

Published: Updated: Author: Ontario Protocol

Ontario Protocol is an x402-native marketplace for AI agent commerce. This document describes how the components fit together — the paid endpoints, the discovery layer, the Coinbase facilitator integration, the take-rate proxy, and the on-chain reputation surface via EAS on Base.

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.