coal
coal

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

  1. Agent has a wallet — funded with USDC on Base (via Privy server wallet or raw key)
  2. Agent discovers — browses merchants via the Discovery API
  3. Agent pays — direct transfer (for checkouts) or x402 (for paywalls)
  4. 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.

typescript
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

bash
1GET /api/agent/wallet
2# → { "address": "0x993...", "balance": "14.20", "network": "base" }

Step 2: Create Checkout

bash
1POST /api/agent/checkout
2{ "amount": 0.10, "productName": "F1 Figurine", "currency": "USDC" }
3# → { "id": "cmn...", "amount": "0.10", "status": "pending" }

Step 3: Send USDC On-Chain

typescript
1const hash = await walletClient.writeContract({
2 address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
3 abi: erc20Abi,
4 functionName: 'transfer',
5 args: [merchantPayoutAddress, parseUnits('0.10', 6)]
6});

Step 4: Confirm & Verify

bash
1POST /api/pay/confirm
2{ "sessionId": "cmn...", "txHash": "0xabc...", "payerAddress": "0x993..." }
3
4GET /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:

typescript
1import { payX402Paywall } from './lib/wallet';
2
3const 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

bash
1GET https://oracle.usecoal.xyz/api/price/ETH

The server replies 402 with the standard x402 envelope:

json
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

typescript
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};
9
10// Sign over USDC's EIP-712 domain — this is off-chain, no gas
11const 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

typescript
1const xPayment = Buffer.from(JSON.stringify({
2 x402Version: 1,
3 scheme: 'exact',
4 network: 'eip155:8453',
5 payload: { signature, authorization },
6})).toString('base64');
7
8const res = await fetch(verifyUrl, {
9 method: 'POST',
10 headers: { 'X-PAYMENT': xPayment, 'content-type': 'application/json' },
11 body: '{}',
12});
13
14// X-PAYMENT-RESPONSE header carries the on-chain tx hash
15const 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=

bash
1GET https://oracle.usecoal.xyz/api/price/ETH?address=0x993...
2# → 200 with the gated payload

Security

ProtectionHow
Per-tx cap$5 max enforced in wallet code
Rate limit10 payments/minute
Balance checkFails fast if insufficient USDC
User confirmationAgent asks before spending > $0.50
Privy policiesAllowlisted recipients, daily caps
x402 nonce checkCoal verifies authorizationState() on-chain before submitting
x402 amount checkCoal rejects authorizations below the paywall price
x402 window checkCoal rejects authorizations outside validAfter/validBefore

Coal Agent SDK Tools

The coal-agent example app exposes these OpenAI function-calling tools:

ToolDescription
discover_merchantsBrowse marketplace for merchants/products/paywalls
get_agent_walletCheck wallet address and USDC balance
create_checkoutCreate a checkout session
execute_paymentPay a checkout via direct USDC transfer (max $5)
pay_x402_paywallPay an x402 paywall via EIP-3009 (gasless, max $5)
fetch_paywall_contentFetch protected content after payment
verify_receiptGet 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.