m2m-exchange
Machine-to-machine payment exchange built on Cloudflare Workers + the
x402 payment protocol (HTTP 402, USDC micropayments). Buyer agents pay
per-request; seller agents expose paid APIs behind an edge gateway.
Phase 0 (this repo): one working end-to-end paid HTTP request on the
Base Sepolia testnet — a buyer agent script pays USDC via x402 to call a demo
seller API behind a gateway worker.
Live deployment (testnet): https://m2m-gateway.akrivis.workers.dev
Free probe: curl https://m2m-gateway.akrivis.workers.dev/healthz
Seller wallet (receives test USDC): 0x417Da74CDc0D3BabF6AdC851b6E5c638574c0D58
Testnet USDC only — no mainnet, no real funds.
Architecture
HTTP GET /api/weather
┌──────────────────────────────────────────┐
│ ▼
┌─────────────┐ 402 + payment requirements ┌────────────────────┐
│ buyer agent │ ◄───────────────────────────── │ gateway worker │
│ (x402-fetch │ │ (Cloudflare │
│ + viem) │ GET + X-PAYMENT (EIP-3009 │ Workers + Hono │
│ │ ─────────────────────────────► │ + x402-hono │
│ pays USDC │ signed authorization) │ middleware) │
└─────────────┘ └─────────┬──────────┘
│ │ verify+settle
│ ┌───────▼──────────┐
└─────────── USDC on Base Sepolia ───────► │ facilitator │
(settled on-chain, 200 OK + │ (x402.org public │
X-PAYMENT-RESPONSE receipt) │ testnet service)│
└──────────────────┘
The gateway fronts the demo seller API. For P0 the demo paid endpoints live
inside the gateway worker itself (no separate seller worker — deliberately
kept simple).
The 402 flow
- Buyer sends a plain request to a paid route.
- Gateway responds
402 Payment Required with a JSON body:
{ x402Version: 1, accepts: [ { scheme: "exact", network: "base-sepolia", maxAmountRequired: "1000", payTo, asset, ... } ], error }.
x402-fetch picks a requirement, signs an EIP-3009 transferWithAuthorization
for the USDC amount with the buyer wallet, and retries with an
X-PAYMENT header.
- The gateway's
paymentMiddleware asks the facilitator to verify and settle
the payment on Base Sepolia, then runs the route handler and returns
200 OK with the payload plus an X-PAYMENT-RESPONSE receipt header
(tx hash, network, payer).
Repository layout
m2m-exchange/
package.json # npm workspaces root (dev, test, typecheck, buy)
tsconfig.base.json
.dev.vars.example # documented placeholders — no real keys
protocol/
PROTOCOL.md # M2M/1 commerce protocol spec (state machine, messages)
schemas/ # JSON Schema (2020-12) for every M2M/1 message
workers/
gateway/ # Hono gateway + x402 payment middleware
src/index.ts # /healthz (free), /api/weather + /api/echo ($0.001)
test/index.spec.ts # vitest, runs inside the Workers runtime
wrangler.toml # name "m2m-gateway", nodejs_compat
packages/
protocol/ # @m2m/protocol: shared M2M/1 TS types (zero deps)
src/index.ts # messages, TxState, error codes, §6.4 guard helpers
buyer/
src/buyer.ts # Node CLI: pays USDC and fetches a paid endpoint
Prerequisites
- Node.js >= 20 (developed on v24)
- Two Base Sepolia test wallets (one buyer, one seller). Any EVM wallet tool
can generate them; never reuse mainnet keys.
- Testnet USDC in the buyer wallet from the Circle faucet:
https://faucet.circle.com (select Base Sepolia, paste the buyer address).
$0.10 of test USDC pays for ~100 requests at $0.001.
Setup
npm install
cp .dev.vars.example workers/gateway/.dev.vars
The buyer's private key is not read by wrangler — export it in your shell:
export BUYER_PRIVATE_KEY=0x<buyer wallet private key>
export GATEWAY_URL=http://localhost:8787
Run your first paid request
Terminal 1 — start the gateway locally:
Terminal 2 — run the buyer agent:
npm run buy
npm run buy -- /api/echo
The buyer prints the raw 402 payment requirements, the paid response body,
and the on-chain payment receipt. Free route for comparison:
curl http://localhost:8787/healthz
Verify
npm run typecheck
npm test
Unit tests cover: /healthz is free, paid routes return 402 with payment
requirements, and the 402 body matches the x402 spec (x402Version,
accepts[] with scheme/network/amount/payTo/asset). No on-chain settlement
is attempted in tests.
x402 packages used
| package | version | role |
|---|
x402 | ^1.2.0 | protocol core (types, schemes, facilitator) |
x402-hono | ^1.2.0 | server paymentMiddleware for Hono |
x402-fetch | ^1.2.0 | client wrapFetchWithPayment |
viem | ^2.55.x | wallet/signing (used by x402 and the buyer) |
hono | ^4.13.x | gateway HTTP framework |
Notes:
- Newer scoped
@x402/* packages exist on npm (v2.x line); this repo pins the
documented v1 line (x402, x402-hono, x402-fetch), which the brief
targets.
- The facilitator defaults to the public testnet facilitator at
https://x402.org/facilitator (built into the x402 package) — no API key
required. To use a different facilitator (e.g. Coinbase CDP), set
FACILITATOR_URL in workers/gateway/.dev.vars.
- Payment network is
base-sepolia; price is $0.001 (1000 USDC base units)
per call.
Roadmap
- P1 — seller registry (who sells what, at what price), Cloudflare D1 for
registry/metadata storage, typed buyer/seller SDKs wrapping the raw x402
flow, service discovery endpoint.
- P2 — Durable Object clearing ledger for per-pair netting (aggregate many
micropayments, settle net amounts on-chain periodically instead of paying
gas per request), reconciliation jobs, dispute/audit trail.