One trace.
Three rails.
Every agent.
AgentWallet connects account, principal and agent records with payment interfaces and route-specific authorization. AP2 mandates, x402 signing and card or payout execution are separate paths; not every payment is signed by a human, anchored on-chain or written to one shared ledger row.
On-chain trace
Supported execution paths record ledger or activity entries and provider references. On-chain anchoring and trace coverage must be verified for the selected route.
Portable agent score
Agent records identify ownership and configured resources. A production reputation score is not established by this implementation.
One model, three rails
Fiat payouts, card payments and configured USDC payments use distinct execution paths. Supported spend-gated routes check per-transaction, daily and monthly caps and can require approval. Generic x402.pay_url has an optional per-call maximum, not the mandate-bound spend gate.
ERC-native
The x402 signing implementation uses EIP-712 typed data and EIP-3009 authorization on configured networks. Other token standards and gas-sponsored operations are not universal platform capabilities.
AP2 mandates
The implementation signs and verifies AP2 mandates. Signer identity and key handling depend on the flow; this does not establish a human WebAuthn signature for every mandate.
Application audit records
Ledger and activity records support investigation. Coverage and database-level immutability depend on the path and deployment permissions.
Company → Principal → Agent
Three identity tiers, programmed into the protocol. Money never moves outside this hierarchy. KYB lives at the Company. Authority lives at the Principal. Execution lives at the Agent.
Company (tenant)
- Who
- the legal entity. KYB-verified, beneficial owners on file, treasury accounts attached.
- Holds
- master fiat float, USDC treasury wallet, billing relationship with Payouts.com, default policy tree.
- On-chain
- Account, principal and agent records are application identities; on-chain registration depends on the configured network and integration.
- Programmable
- create / disable Principals, set tenant-wide spending caps, rotate signing keys, export the full trace.
Principal (human)
- Who
- A principal represents the human or service associated with an agent. Verification and signing requirements depend on the configured flow.
- Holds
- a sub-budget allocated by the Company, a list of Agents they own, a personal policy.
- On-chain
- Principal-to-agent ownership is represented in application records; on-chain registration is configuration-dependent.
- Programmable
- Create and manage agents and use supported mandate and approval interfaces.
Agent (machine)
- Who
- an autonomous AI agent. Holds an API key (pak_…) and an MCP endpoint.
- Holds
- its own fiat wallet, USDC wallet, virtual card, inbox, phone number — all scoped to one Principal.
- On-chain
- Agent identity and optional registration depend on the configured identity integration.
- Programmable
- Use tools and payment paths enabled by the agent's permissions, resources and signer configuration.
Identity → Mandate → Money
Identity, authorization and execution are architectural concerns. Their implementation and enforcement differ by route.
Identity & Trust
Company, Principal and Agent registries. KYB at the Company tier; KYC at the Principal tier; software identity (PAK + ERC-721 NFT) at the Agent tier.
Mandates & Policy
The Agent proposes a payment. The Principal (or pre-signed mandate) authorizes it. The Spending Policy engine evaluates per-call, per-day, per-counterparty, per-rail caps. The decision is signed.
Money Movement
The signed mandate is dispatched to the matching rail. Fiat goes through Payouts.com's regulated network. Cards through the issuer. USDC and stablecoins on Base / Ethereum / Polygon / Arbitrum / Optimism.
One trace ID.
Every rail. Forever.
The trace is the canonical identifier of an agent payment. It is generated at mandate time, anchored on Base, and carried by every downstream system — fiat, card, or crypto — so the audit is reconstructible from a single key.
What's in a trace
- trace_id
- 32 bytes, keccak256(mandate_json). Globally unique. Anchored on Base.
- mandate
- the signed AP2 PaymentMandate or x402 EIP-3009 authorization.
- actors
- (company_id, principal_id, agent_id, counterparty_id).
- policy_decision
- which Spending Policy approved it, with the matched rule ID and the cap consumed.
- rail
- one of ach, sepa, fps, swift, card_push, card_virtual, usdc_base, usdc_eth, x402, internal.
- settlement
- the rail-native reference: tx hash, ACH trace #, card auth code, MoneySend transaction ID.
- state_history
- append-only log of proposed → authorized → submitted → settled / failed / refunded / reversed.
- score_delta
- the contribution this payment made to the Agent's on-chain score.
trace = {
trace_id: "0xa3f1…7c",
company_id: "co_42",
principal_id: "pr_9",
agent_id: "ag_7b",
mandate: { type: "PaymentMandate", sig: "0x…", anchor_tx: "0x9f2a…" },
policy: { rule: "per_call_max_50_usd", consumed: "12.40" },
rail: "usdc_base", // or "ach", "card_virtual", "x402", …
settlement: "0x4d2…e1", // or "ACH-2026-0512-000871", "MC-AUTH-71B"
state: "settled",
score_delta: +3
}Agents earn reputation.
Counterparties read it before accepting payment.
Every Agent has a public 0–1000 score that decays without activity and grows with clean settled volume. Counterparties — MCP servers, x402 endpoints, marketplace vendors — query the score before accepting a 402, just like a card network checks a BIN.
| Signal | Weight | Direction |
|---|---|---|
| Cumulative settled volume (USD-equiv, 90d) | +250 max | + |
| Successful settlements / proposed mandates ratio | +200 max | + |
| Disputes / chargebacks (rolling 180d) | −300 max | - |
| Mandate revocations / fraud flags | −250 max | - |
| Principal KYB tier (Tier 1 / 2 / 3) | +150 max | + |
| Agent age (days since identity issuance) | +100 max | + |
| Policy compliance (declared vs actual spend pattern) | +150 max | + |
| Inactivity decay (no settled volume in 30d) | −2 / day | - |
The score is published as an ERC-1155 metadata field on the Agent's identity NFT and exposed as an MCP tool: agentwallet.score(agent_id) → { score, tier, last_updated, anchor_tx }. Counterparties can require a minimum score for an Agent to call their service.
Connects to every ERC standard agents actually need.
The protocol is opinionated about what an agent needs, and unopinionated about which chain it lives on. Every relevant ERC is mapped to a primitive in the Mandate → Policy → Rail pipeline.
| Standard | What it gives the agent | Where the protocol uses it |
|---|---|---|
| ERC-20 | USDC, EURC, USDT and 50+ stablecoin balances | Crypto wallet, x402 settlement |
| ERC-721 | Unique identity NFT per Agent — portable across platforms | Agent identity, score metadata anchor |
| ERC-1155 | Multi-token (license, capability, credential) bundles | Capability grants, score history |
| EIP-712 | Typed-data signing (human-readable signatures) | All AP2 mandates and policy decisions |
| EIP-2612 | ERC-20 permit — no separate approve tx | Gas-efficient stablecoin spends |
| EIP-3009 | transferWithAuthorization — signed transfer over HTTP | x402 settlement primitive |
| ERC-4337 | Account abstraction — gas sponsorship, batched ops | Gas-sponsored agent transactions |
| ERC-5267 | EIP-712 domain discovery | Cross-platform mandate verification |
Fiat · Card · Crypto — same protocol, different rail.
The differences your engineers actually care about. Same Mandate. Same Policy. Same trace. Different settlement physics. Pick the right rail per call — or let the policy engine route automatically.
| Property | Fiat (ACH / SEPA / FPS / SWIFT) | Card (eligible virtual card / push-to-card) |
|---|---|---|
| Settlement time | seconds (FPS) → 3 days (ACH/SEPA) → 1–5d (SWIFT) | authorization in ms; capture in 1–3 days |
| Reversibility | ACH return up to 60d; SEPA recall window | chargebacks up to 120d |
| Per-call cost | $0.20 – $5 fixed | 2.0 – 3.5% + fixed interchange |
| Identity surface | bank account + name match | PAN, expiry, CVV, 3DS challenge |
| M2M friendliness | batch-friendly; not per-API-call | good for SaaS subscriptions; bad for sub-cent |
| Geo coverage | eligible destinations via configured providers | ~210 countries, MC + push-to-card |
| Property | Crypto (USDC / EURC / x402 / on-chain) | How the protocol abstracts it |
|---|---|---|
| Settlement time | ~2s on Base, ~12s on Ethereum mainnet | Mandate → settlement state in single API call |
| Reversibility | irreversible — refund is a new tx | Trace links original + refund as one logical record |
| Per-call cost | ~$0.001 (Base L2) → $1+ (mainnet) | Gas sponsored by AgentWallet, capped per agent |
| Identity surface | EOA address + EIP-3009 signature | Wrapped by Agent identity NFT + Principal mandate |
| M2M friendliness | native — sub-cent payments per API call | x402 is the default for agent ↔ agent / agent ↔ API |
| Geo coverage | global, no banking rails required | Off-ramp availability requires provider confirmation |
Every Principal. Every Agent.
The same six verbs.
The protocol exposes the same six verbs regardless of identity tier. The Principal API is REST + OIDC. The Agent API is the same shape, plus an MCP wrapper so agents call them as tools.
// 1. Identity
company.create({ legal_name, kyb_docs }) → company_id
company.principal.create({ company_id, name, email, webauthn_pubkey }) → principal_id
principal.agent.create({ principal_id, name, policy }) → { agent_id, pak, mcp_url }
// 2. Mandate (signed by the Principal's WebAuthn key)
principal.mandate.intent({ agent_id, intent, max_value, expires_at, sig }) → mandate_id
agent.mandate.cart({ items, counterparty }) → cart_id // requires Principal sig if > cap
agent.mandate.payment({ cart_id, rail }) → payment_mandate_id
// 3. Policy (evaluated automatically, no call needed; query-able)
policy.evaluate({ mandate, agent_id }) → { decision: "allow"|"deny"|"escalate", rule, cap_consumed }
policy.upsert({ scope: "company"|"principal"|"agent", rules: [...] })
// 4. Rail (the only verb that touches money)
rail.dispatch({ payment_mandate_id }) → { rail, settlement_ref, trace_id, state }
// 5. Trace (single source of truth for audit)
trace.get(trace_id) → full trace object (mandate + policy + rail + state history)
trace.list({ agent_id?, principal_id?, company_id?, since, until }) → trace[]
// 6. Score (read-only, public)
agent.score(agent_id) → { score, tier, last_updated, anchor_tx }MCP tools, REST endpoints and client methods have separate contracts. Check the current tool catalog and API schema. The agent's MCP endpoint at /mcp/agent is scoped to one row in agent_identities — the agent literally cannot call beyond its own identity tier.
The mandate chain
Intent → Cart → Payment
The Agent Payments Protocol uses ES256-signed JWS tokens to make agent intent cryptographically provable. A complete payment is a chain of three signed mandates: Intent → Cart → Payment. Every signature is verified against the agent's published JWK and audited.
IntentMandate
"I authorize agent X to spend ≤ $Y for purpose Z"
CartMandate
Specific items + merchant + total + intent_id
PaymentMandate
Rail + recipient + cart_id + final amount
{
"iss": "did:agentwallet:ag_01J…", // agent identity
"sub": "[email protected]",
"aud": "https://vendor.example/ap2/v1",
"iat": 1746345600,
"exp": 1746349200, // 1 hour
"jti": "01J9…uuidv7",
"mandate_type": "payment",
"intent_id": "01J9intent…",
"cart_id": "01J9cart…",
"rail": "x402_usdc_base",
"amount": { "value": "125.00", "currency": "USD" },
"recipient": { "address": "0xabc…" }
}
// Header
{ "alg": "ES256", "kid": "ag_01J9…#k1", "typ": "JWS" }MCP & discovery
Per-agent tool catalog.
Each agent has its own MCP endpoint at /mcp/agent, scoped to one row in agent_identities. Drop the URL and the agent's pak_… key into any MCP-compatible client and the agent is online.
| Tool | What it does | Limit-gated? |
|---|---|---|
| wallet.status | Computed balance + holds + headroom | — |
| wallet.send_payment | Initiate fiat payout via available rail | yes |
| wallet.send_usdc | USDC transfer on Base via CDP | yes |
| wallet.x402_pay | Sign EIP-3009 auth for x402 endpoint | yes |
| wallet.list_activity | Recent transactions across sources | — |
| wallet.request_approval | Surface pending action to Principal widget | — |
| card.details | Last4 + balance + status (no PAN) | — |
| card.recent_authorizations | Card-level transactions only | — |
| comms.send_sms | Outbound SMS via telephony provider | — |
| comms.send_email | Outbound email via email provider | — |
| comms.list_inbox | Unread inbound messages | — |
| identity.who_am_i | Agent metadata + AP2 public key | — |
| identity.sign_mandate | ES256 sign an AP2 IntentMandate | — |
| identity.discover | Resolve another agent via .well-known | — |
| approvals.poll | Check status of a pending approval | — |
Discovery · /.well-known/agent.json
Agentic Commerce Protocol describes merchant checkout interactions. Agent identity and capability discovery are separate interfaces, not an Agentic Commerce Protocol standard.
{
"agent_id": "did:agentwallet:ag_01J9…",
"name": "Acme Procurement Agent",
"public_keys": [
{ "kid": "ag_01J9…#k1", "alg": "ES256",
"jwk": { "kty": "EC", "crv": "P-256", "x": "…", "y": "…" }
}
],
"endpoints": {
"ap2_inbound": "https://agent.acme.example/ap2/v1/payment",
"a2a": "https://agent.acme.example/a2a/v1"
},
"accepts": ["x402_usdc_base", "spt", "ach"],
"erc8004": { "chainId": 8453, "tokenId": "42" }
}Distinct payment paths with route-specific authorization.
Outbound payments leave through one of three protocol stacks. The choice is decided by the merchant's capability advertisement (or by the rail the agent's policy permits).
x402 over EIP-3009
The merchant returns HTTP 402 Payment Required with a payment offer. The agent signs an EIP-3009 transferWithAuthorization (USDC on Base) for the offered amount and replays the request with the signed authorization in the X-PAYMENT header.
// 1. Agent's first request
GET /api/dataset/v1 HTTP/1.1
Host: data.example
Authorization: Bearer pak_…
// 2. Merchant returns 402 with offer
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"x402": {
"amount": "0.10", "currency": "USDC",
"network": "base",
"recipient": "0xabc…",
"validBefore": 1746349200
}
}
// 3. Agent signs EIP-3009 (CDP-managed key) and replays
GET /api/dataset/v1 HTTP/1.1
Host: data.example
X-PAYMENT: eyJ0eXAiOiJ4NDAyIiwiYWxnIjoi… // signed authShared Payment Tokens (SPT)
For card-rail payments to merchants that accept network-issued single-use tokens. The agent requests an SPT, scoped to a single use and to a specific merchant + amount. The token expires; replay is structurally impossible.
const spt = await issuer.paymentTokens.create({
type: 'card',
card: { vault_alias: card.vaultAlias },
single_use: true,
restrictions: {
amount: cartTotalCents,
merchant: merchantId,
expires_at: Math.floor(Date.now() / 1000) + 300
}
});
// Persist for audit
await db.insert(acpSptIssuances).values({
agentIdentityId, tokenId: spt.id,
cartMandateId, amountCents: cartTotalCents
});Why a protocol — not just an API.
An API is a wrapper around money movement. A protocol is a contract about who moved it, why they were allowed to, and how it can be replayed. Without that contract, agent commerce is unauditable. With it, an Agent can transact with another Agent at any company on any rail, and both sides can prove what happened.