Skip to main content
An AI agent calls a paywalled API. The merchant responds with HTTP 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 the walletId 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

What you’ll need

  • A DFNS account
  • A service account with these permissions:
    • Wallets:GenerateSignature on the customer (payer) wallet
    • Wallets:BroadcastTransaction on the merchant wallet
    • Wallets:Read on 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

1

Clone and install

2

Set up environment variables

.env
To find your wallet IDs:

Run the demo

You’ll see the console walk through each step:
  1. The agent hits the merchant and receives 402 with a PaymentRequirement
  2. The signer validates the requirement against its policy cap, then calls wallets.generateSignature with kind: 'Eip712'
  3. The agent retries with the signature in an X-PAYMENT header
  4. The merchant verifies the signature locally with ethers.verifyTypedData
  5. The facilitator encodes receiveWithAuthorization and calls wallets.broadcastTransaction from the merchant wallet
  6. The transaction hash is printed. Paste it into sepolia.etherscan.io to confirm settlement.

Two DFNS wallets, two roles

The merchant wallet’s on-chain address must equal MERCHANT_ADDRESS. USDC enforces msg.sender == payee inside receiveWithAuthorization, so only the merchant can settle.

How the signer works

The in-process cap is your first line of defense. For production, layer a DFNS policy on 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

The merchant wallet is the only entity authorized to call 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 until validBefore 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 DFNS Wallets: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 per 402 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 for ReceiveWithAuthorization 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.

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
Last modified on June 8, 2026