The AgentWallet Protocol

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.

01

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.

02

Portable agent score

Agent records identify ownership and configured resources. A production reputation score is not established by this implementation.

03

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.

04

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.

05

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.

06

Application audit records

Ledger and activity records support investigation. Coverage and database-level immutability depend on the path and deployment permissions.

The hierarchy

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.

Tier 1

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.
Tier 2

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.
Tier 3

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.
The 3-rail programming model

Identity  →  Mandate  →  Money

Identity, authorization and execution are architectural concerns. Their implementation and enforcement differ by route.

Layer 1

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.

Outputs
a verifiable (company_id, principal_id, agent_id) tuple, the Principal's public key, and the Agent's current on-chain score.
Standards
EIP-712, ERC-721 / ERC-1155 (optional identity NFTs), DID, OIDC for Principals (Auth0 today).
Layer 2

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.

Outputs
a signed AP2 PaymentMandate or EIP-3009 authorization, plus a policy decision record.
Standards
Google AP2 (IntentMandate / CartMandate / PaymentMandate), x402, EIP-3009 transferWithAuthorization, EIP-2612 permits.
Layer 3

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.

Outputs
a settlement reference (tx hash, ACH trace number, card auth code), reconciled into the unified ledger row.
Standards
ACH NACHA, SEPA, Faster Payments, SWIFT MT103, Mastercard MoneySend, ERC-20 transfer, x402 HTTP.
The trace protocol

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.
// One trace, regardless of railjs
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
}
The scoring protocol

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.

SignalWeightDirection
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.

ERC interop

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.

StandardWhat it gives the agentWhere the protocol uses it
ERC-20USDC, EURC, USDT and 50+ stablecoin balancesCrypto wallet, x402 settlement
ERC-721Unique identity NFT per Agent — portable across platformsAgent identity, score metadata anchor
ERC-1155Multi-token (license, capability, credential) bundlesCapability grants, score history
EIP-712Typed-data signing (human-readable signatures)All AP2 mandates and policy decisions
EIP-2612ERC-20 permit — no separate approve txGas-efficient stablecoin spends
EIP-3009transferWithAuthorization — signed transfer over HTTPx402 settlement primitive
ERC-4337Account abstraction — gas sponsorship, batched opsGas-sponsored agent transactions
ERC-5267EIP-712 domain discoveryCross-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.

PropertyFiat (ACH / SEPA / FPS / SWIFT)Card (eligible virtual card / push-to-card)
Settlement timeseconds (FPS) → 3 days (ACH/SEPA) → 1–5d (SWIFT)authorization in ms; capture in 1–3 days
ReversibilityACH return up to 60d; SEPA recall windowchargebacks up to 120d
Per-call cost$0.20 – $5 fixed2.0 – 3.5% + fixed interchange
Identity surfacebank account + name matchPAN, expiry, CVV, 3DS challenge
M2M friendlinessbatch-friendly; not per-API-callgood for SaaS subscriptions; bad for sub-cent
Geo coverageeligible destinations via configured providers~210 countries, MC + push-to-card
PropertyCrypto (USDC / EURC / x402 / on-chain)How the protocol abstracts it
Settlement time~2s on Base, ~12s on Ethereum mainnetMandate → settlement state in single API call
Reversibilityirreversible — refund is a new txTrace links original + refund as one logical record
Per-call cost~$0.001 (Base L2) → $1+ (mainnet)Gas sponsored by AgentWallet, capped per agent
Identity surfaceEOA address + EIP-3009 signatureWrapped by Agent identity NFT + Principal mandate
M2M friendlinessnative — sub-cent payments per API callx402 is the default for agent ↔ agent / agent ↔ API
Geo coverageglobal, no banking rails requiredOff-ramp availability requires provider confirmation
The programming model

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.

~/agentwallet — six verbstypescript
// 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"

Principal-signed
②

CartMandate

Specific items + merchant + total + intent_id

Agent-signed (under intent)
③

PaymentMandate

Rail + recipient + cart_id + final amount

Agent-signed (under cart)
PaymentMandate JWS payloadjws
{
  "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.

ToolWhat it doesLimit-gated?
wallet.statusComputed balance + holds + headroom—
wallet.send_paymentInitiate fiat payout via available railyes
wallet.send_usdcUSDC transfer on Base via CDPyes
wallet.x402_paySign EIP-3009 auth for x402 endpointyes
wallet.list_activityRecent transactions across sources—
wallet.request_approvalSurface pending action to Principal widget—
card.detailsLast4 + balance + status (no PAN)—
card.recent_authorizationsCard-level transactions only—
comms.send_smsOutbound SMS via telephony provider—
comms.send_emailOutbound email via email provider—
comms.list_inboxUnread inbound messages—
identity.who_am_iAgent metadata + AP2 public key—
identity.sign_mandateES256 sign an AP2 IntentMandate—
identity.discoverResolve another agent via .well-known—
approvals.pollCheck 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.

capabilities documentjson
{
  "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.

x402 round triphttp
// 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 auth

Shared 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.

SPT issuancetypescript
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.

Build on the protocol.