An AI agent calls a paywalled API. The merchant responds with HTTPDocumentation Index
Fetch the complete documentation index at: https://docs.dfns.co/llms.txt
Use this file to discover all available pages before exploring further.
402 Payment Required and a payment requirement (amount, asset, recipient, nonce). The agent forwards the requirement to a Dfns-powered signer, which validates it against your policy and produces an EIP-712 signature for ERC-3009 ReceiveWithAuthorization. The agent retries the call with the signature in an X-PAYMENT header. The merchant verifies the signature and broadcasts settlement from its own Dfns wallet, paying the gas itself.
The X402 protocol revives HTTP 402 as a wire format for agent ↔ merchant payments. Dfns provides the two wallets the flow needs: a payer wallet that signs the authorization without ever exposing the key, and a merchant wallet that broadcasts the settlement. Policies run before signing, so agents cannot exceed the spending limits you set.
Get the code
dfns/dfns-solutions: x402-ai-payments
When to use this
- Agent-driven micropayments: AI agents that pay per API call, per article, per inference
- Gasless UX for agents: agents hold only the asset they spend (USDC), not native gas
- Policy-gated autonomy: enforce per-payment caps, recipient allowlists, and asset whitelists before any signature is produced
How it works
The two Dfns roles share the same API client in the reference implementation: only thewalletId differs between the generateSignature call (payer wallet) and the broadcastTransaction call (merchant wallet). In production, the Signer typically runs on the platform that hosts the agent, while the Facilitator runs on the merchant.
Reference implementation
| Component | Technology |
|---|---|
| Signing | Dfns KMS via @dfns/sdk (EIP-712) |
| Settlement | Dfns wallets.broadcastTransaction from the merchant wallet |
| Standard | ERC-3009 receiveWithAuthorization on Circle USDC (FiatTokenV2) |
| Scripts | TypeScript via ts-node, ethers v6 |
| Network | Ethereum Sepolia (Chain ID 11155111) |
What you’ll need
- A Dfns account
- A service account with these permissions:
Wallets:GenerateSignatureon the customer (payer) walletWallets:BroadcastTransactionon the merchant walletWallets:Readon both
- Two Dfns wallets on Ethereum Sepolia:
- A customer wallet funded with testnet USDC (Circle faucet)
- A merchant wallet funded with testnet ETH for gas
- Node.js v22+
Configuration
Set up environment variables
.env
| Variable | Description |
|---|---|
DFNS_API_URL | Dfns API base URL (api.dfns.io) |
DFNS_ORG_ID | Your Dfns organization ID. See how to find it. |
DFNS_AUTH_TOKEN | Service account auth token |
DFNS_CRED_ID | Service account credential ID |
DFNS_PRIVATE_KEY | Service account private key (PEM) |
DFNS_CUSTOMER_WALLET_ID | Payer wallet. Signs the EIP-712 authorization. |
DFNS_MERCHANT_WALLET_ID | Payee wallet. Broadcasts the settlement. |
MERCHANT_ADDRESS | On-chain address of the merchant wallet (must match DFNS_MERCHANT_WALLET_ID) |
USDC_CONTRACT_ADDRESS | USDC contract on the target chain |
CHAIN_ID | Numeric chain ID (11155111 for Sepolia) |
Run the demo
- The agent hits the merchant and receives
402with aPaymentRequirement - The signer validates the requirement against its policy cap, then calls
wallets.generateSignaturewithkind: 'Eip712' - The agent retries with the signature in an
X-PAYMENTheader - The merchant verifies the signature locally with
ethers.verifyTypedData - The facilitator encodes
receiveWithAuthorizationand callswallets.broadcastTransactionfrom the merchant wallet - The transaction hash is printed. Paste it into sepolia.etherscan.io to confirm settlement.
Two Dfns wallets, two roles
| Role | Wallet | Responsibility |
|---|---|---|
| Payer (customer) | DFNS_CUSTOMER_WALLET_ID | Holds USDC. Signs the EIP-712 authorization via wallets.generateSignature. Never broadcasts. |
| Payee + Facilitator (merchant) | DFNS_MERCHANT_WALLET_ID | Verifies the signature, broadcasts receiveWithAuthorization via wallets.broadcastTransaction, pays gas. |
MERCHANT_ADDRESS. USDC enforces msg.sender == payee inside receiveWithAuthorization, so only the merchant can settle.
How the signer works
Wallets:Sign covering the customer wallet. It runs server-side at Dfns and cannot be bypassed even if the signer service is compromised.
How the facilitator works
receiveWithAuthorization. USDC’s contract enforces msg.sender == payee. This is the security model that makes pull payments safe: a signed authorization is worthless to anyone other than the named payee.
Design considerations
Enforce policy before signing
A signed authorization is irrevocable untilvalidBefore expires. Validate the requirement (amount, recipient, asset, chain) before calling wallets.generateSignature. The reference implementation enforces a per-payment cap; production should also check recipient allowlists, per-merchant caps, and a time-windowed spend budget.
Layer with a Dfns policy
In-process checks live in the same process as the signer. If that process is compromised, the checks are bypassed. A DfnsWallets:Sign policy on the customer wallet runs on Dfns infrastructure and cannot be bypassed by your service. Use both: the in-process check is fast and expressive; the Dfns policy is the safety net.
Unique nonces per requirement
ERC-3009 uses the nonce to prevent replay. The merchant must generate a fresh random nonce per402 response, and the customer’s wallet should refuse to sign two requirements with the same nonce. The reference implementation uses ethers.randomBytes(32).
Pin the verifying contract
A signature forReceiveWithAuthorization is bound to a verifyingContract in the EIP-712 domain. Treat that field as an allowlist: the signer should refuse to sign for any contract address it doesn’t recognize. Otherwise an attacker who controls the 402 response can redirect signatures to a contract they control.
Treat gas as an operational cost
The merchant pays gas for every settlement. In a high-volume X402 deployment, this is non-trivial: budget it explicitly, monitor it per merchant, and consider passing it through in pricing the same way card networks pass through interchange.Related
Define treasury policies
Spending limits and approval quorums
Build programmable approval policies
Service accounts that decode call data
Automate payments
Policy-gated outbound transfers
Wallets API
generateSignature and broadcastTransaction reference