Autonomous Agent Payments
Coal enables AI agents to pay for products and services autonomously — real USDC on Base, no human interaction needed. Two flows are supported:
- Direct USDC — agent sends USDC to a merchant payout address for a Coal checkout session
- x402 paywalls — agent signs an EIP-3009 authorization, Coal settles on-chain as facilitator (gasless for the agent)
How It Works
- Agent has a wallet — funded with USDC on Base (via Privy server wallet or raw key)
- Agent discovers — browses merchants via the Discovery API
- Agent pays — direct transfer (for checkouts) or x402 (for paywalls)
- Agent verifies — receipt published to 0G Storage, anchored on 0G Chain
Agent Wallet Setup
Privy Server Wallets (Recommended)
Coal uses Privy server wallets for agent wallets. Keys are secured in TEE enclaves — never exposed.
1// Create a server wallet (one-time)2const wallet = await privy.wallets.create({ chain_type: 'ethereum' });3// wallet.address = "0x99301e..."
Fund & Withdraw
- Fund: Send USDC on Base to the agent wallet address
- Withdraw: Agent can send remaining USDC to any address via
POST /api/agent/wallet/withdraw - Users can always withdraw — Privy wallets are self-custodial
Flow A — Direct USDC (Checkouts)
Step 1: Check Balance
1GET /api/agent/wallet2# → { "address": "0x993...", "balance": "14.20", "network": "base" }
Step 2: Create Checkout
1POST /api/agent/checkout2{ "amount": 0.10, "productName": "F1 Figurine", "currency": "USDC" }3# → { "id": "cmn...", "amount": "0.10", "status": "pending" }
Step 3: Send USDC On-Chain
1const hash = await walletClient.writeContract({2 address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base3 abi: erc20Abi,4 functionName: 'transfer',5 args: [merchantPayoutAddress, parseUnits('0.10', 6)]6});
Step 4: Confirm & Verify
1POST /api/pay/confirm2{ "sessionId": "cmn...", "txHash": "0xabc...", "payerAddress": "0x993..." }34GET /api/receipts/{sessionId}5# → { "verified": true, "proofTrail": { "storage": {...}, "chain": {...} } }
The receipt includes a 3-step proof trail: Base TX → 0G Storage → 0G Chain anchor.
Flow B — x402 Paywalls (Gasless)
For paywall-protected resources, the agent uses the x402 protocol. Coal acts as the facilitator: the agent signs off-chain, Coal submits the on-chain transferWithAuthorization via its operator wallet — so the agent wallet never needs ETH.
One-shot helper
If you're using the coal-agent example as a starting point, the payX402Paywall() helper does steps 1–3 below in a single call:
1import { payX402Paywall } from './lib/wallet';23const result = await payX402Paywall(walletId, {4 verifyUrl: 'https://api.usecoal.xyz/api/paywalls/pw_oracle_price_feed/verify',5 priceUsd: 0.01,6 payTo: '0xMerchantPayoutAddress...',7});8// → { txHash, payer, payTo, network, body, response, explorerUrl }
Manual flow
1. Trigger 402
1GET https://oracle.usecoal.xyz/api/price/ETH
The server replies 402 with the standard x402 envelope:
1{2 "x402Version": 1,3 "accepts": [4 {5 "scheme": "exact",6 "network": "eip155:8453",7 "maxAmountRequired": "10000",8 "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",9 "payTo": "0xMerchantPayoutAddress...",10 "resource": "https://oracle.usecoal.xyz/api/price/ETH",11 "description": "Price data for ETH",12 "mimeType": "application/json",13 "maxTimeoutSeconds": 60,14 "extra": { "name": "USD Coin", "version": "2" }15 }16 ]17}
2. Sign EIP-3009 with the agent wallet
1const authorization = {2 from: agentAddress,3 to: payTo,4 value: '10000', // base units (USDC, 6 decimals)5 validAfter: '0',6 validBefore: String(Math.floor(Date.now() / 1000) + 300),7 nonce: '0x' + crypto.randomBytes(32).toString('hex'),8};910// Sign over USDC's EIP-712 domain — this is off-chain, no gas11const signature = await privy.wallets().ethereum().signTypedData(walletId, {12 params: {13 typed_data: {14 domain: { name: 'USD Coin', version: '2', chainId: 8453, verifyingContract: USDC_ADDRESS },15 types: { TransferWithAuthorization: [16 { name: 'from', type: 'address' },17 { name: 'to', type: 'address' },18 { name: 'value', type: 'uint256' },19 { name: 'validAfter', type: 'uint256' },20 { name: 'validBefore', type: 'uint256' },21 { name: 'nonce', type: 'bytes32' },22 ]},23 primary_type: 'TransferWithAuthorization',24 message: authorization,25 },26 },27});
3. POST X-PAYMENT to verify URL
1const xPayment = Buffer.from(JSON.stringify({2 x402Version: 1,3 scheme: 'exact',4 network: 'eip155:8453',5 payload: { signature, authorization },6})).toString('base64');78const res = await fetch(verifyUrl, {9 method: 'POST',10 headers: { 'X-PAYMENT': xPayment, 'content-type': 'application/json' },11 body: '{}',12});1314// X-PAYMENT-RESPONSE header carries the on-chain tx hash15const xpr = JSON.parse(Buffer.from(res.headers.get('x-payment-response')!, 'base64').toString());16// { success: true, transaction: '0x...', network: 'eip155:8453', payer: '0x...' }
4. Retry the resource with ?address=
1GET https://oracle.usecoal.xyz/api/price/ETH?address=0x993...2# → 200 with the gated payload
Security
| Protection | How |
|---|---|
| Per-tx cap | $5 max enforced in wallet code |
| Rate limit | 10 payments/minute |
| Balance check | Fails fast if insufficient USDC |
| User confirmation | Agent asks before spending > $0.50 |
| Privy policies | Allowlisted recipients, daily caps |
| x402 nonce check | Coal verifies authorizationState() on-chain before submitting |
| x402 amount check | Coal rejects authorizations below the paywall price |
| x402 window check | Coal rejects authorizations outside validAfter/validBefore |
Coal Agent SDK Tools
The coal-agent example app exposes these OpenAI function-calling tools:
| Tool | Description |
|---|---|
discover_merchants | Browse marketplace for merchants/products/paywalls |
get_agent_wallet | Check wallet address and USDC balance |
create_checkout | Create a checkout session |
execute_payment | Pay a checkout via direct USDC transfer (max $5) |
pay_x402_paywall | Pay an x402 paywall via EIP-3009 (gasless, max $5) |
fetch_paywall_content | Fetch protected content after payment |
verify_receipt | Get 0G proof trail for a payment |
Live Demo
Try the Coal Agent Demo — click "Buy me something under $1" or "Get me ETH price from the oracle" to see autonomous payments in action.
