Wire protocol
The 402 → sign → pay → receipt flow, and the exact messages on the wire.
APX is x402-compatible from day one. The wire format is pipe-separated, with no JSON and no whitespace ambiguity, so signatures are unambiguous.
The flow
- The agent calls a merchant API. The merchant returns
402 Payment RequiredwithX-Payment-*headers describing the price and resource. - The agent signs a canonical message with its Ed25519 key and posts it to the gateway
/pay. - The gateway verifies the signature, checks the rules, moves the money, and returns a gateway-signed receipt.
- The agent retries the merchant with an
X-Payment-Receiptheader. The merchant verifies the receipt and serves the response.
Canonical messages
The agent signs this exact string:
agentpay.payment.v1|<agent_id>|<merchant_id>|<amount_cents>|USD|<resource>|<nonce>
The gateway signs the receipt it returns:
agentpay.receipt.v1|<receipt_id>|<agent_id>|<merchant_id>|<amount_cents>|USD|<resource>|<nonce>|<expires_at>
All amounts are integer cents on the wire and in storage. Dollars appear only at SDK ergonomics.
Verifying a receipt
The merchant does not need to call back to the gateway. It fetches the gateway public key once from /pubkey and verifies the Ed25519 signature locally.
import { verifyReceipt } from "@agentpay/merchant";
const ok = verifyReceipt(receipt, gatewayPubkey); // true / false, no round trip
Replay and expiry
Receipts expire in minutes (expires_at is part of the signed message) and are single-use. The agent generates a fresh nonce per request, so a receipt cannot be replayed later.
Identity (KYA)
Each agent also carries a signed identity passport at GET /agent/:id/passport: its public key, owner, mandate, and a gateway signature. Merchants can require verified agents at the door. See How it works.