Agent-to-Agent Payments
Build autonomous AI agents that discover, negotiate, and pay each other for services — settled instantly on Base via PayDirect.
Why Agent-to-Agent Payments?
As AI agents become capable of executing complex workflows autonomously, they need a way to pay other agents for specialized services — data retrieval, content generation, code review, analysis — without waiting for a human to approve each transaction.
PayDirect makes this possible with a simple REST API: one agent creates a payment, the other agent sends tokens, and PayDirect handles detection, fee deduction, and settlement on Base. The entire flow is programmable, verifiable, and completes in seconds.
Agents negotiate price, create invoices, and settle payments entirely programmatically.
Base L2 finality in ~2 seconds. No waiting for bank transfers or payment processor holds.
Every payment is verifiable on-chain. Agents can prove payment before delivering services.
Architecture
The demo uses two independent processes. Agent A is a content generation service (the seller). Agent B is a research aggregator (the buyer). PayDirect sits between them as the settlement layer.
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Agent B │ │ PayDirect │ │ Agent A │
│ (Buyer) │ │ (Settlement) │ │ (Seller) │
└──────┬───────┘ └────────┬─────────┘ └──────┬───────┘
│ │ │
1. │─── POST /services/generate ─────────────────────▶│
│ │ │
│ │◀── createPayment ───────│ 2.
│ │ │
│ │─── paymentId + addr ───▶│ 3.
│ │ │
│◀─────────── invoice (paymentId, address) ────────│ 4.
│ │ │
5. │── Send USDC to addr ──▶│ │
│ (sandbox: auto) │ │
│ │── detect, confirm, │
│ │ deduct fee, forward ─▶│ 6.
│ │ │
7. │── POST /verify ───────▶│ │
│◀── verified: true ─────│ │
│ │ │
8. │── POST /services/deliver ───────────────────────▶│
│ │ │
│◀─────────── generated content ───────────────────│ 9.Steps 1-4: Agent B requests a service. Agent A creates a PayDirect payment and returns an invoice with the receiving address and amount.
Step 5: Agent B sends USDC to the receiving address on Base. In sandbox mode this is auto-completed.
Step 6: PayDirect detects the on-chain transfer, confirms it, deducts the 0.5% fee, and forwards the net amount to Agent A's settlement wallet.
Steps 7-9: Agent B verifies payment, then requests delivery. Agent A double-checks verification and delivers the content.
Agent A: Content Generator (Seller)
Agent A is a lightweight HTTP server that exposes two endpoints. It uses the PayDirect TypeScript SDK to create payments and verify settlement.
Accepts a content request, creates a PayDirect payment invoice, and returns it to the buyer agent.
import PayDirectClient from "@paydirect/sdk";
const client = new PayDirectClient({
apiKey: process.env.TEST_API_KEY,
baseUrl: "http://localhost:3000/api/v1", // or https://paydirect.com/api/v1
});
// When a buyer requests content:
async function handleGenerateRequest(prompt: string, buyerAgent: string) {
const { payment, receivingAddress } = await client.createPayment({
tokenSymbol: "USDC",
amount: "1.00",
merchantWallet: AGENT_WALLET,
description: `Content generation for ${buyerAgent}`,
metadata: {
prompt,
buyerAgent,
sellerAgent: "content-generator-v1",
type: "agent-to-agent",
},
});
// Return an invoice to the buyer
return {
invoice: {
paymentId: payment.id,
receivingAddress,
amount: "1.00",
tokenSymbol: "USDC",
},
};
}Verifies the payment was settled, then delivers the generated content. Returns 402 if payment is not yet verified.
async function handleDeliverRequest(paymentId: string) {
const { verified, payment } = await client.verifyPayment(paymentId);
if (!verified) {
// 402 Payment Required — buyer hasn't paid yet
return { status: 402, error: "Payment not verified" };
}
// Payment confirmed — generate and return content
const content = await generateContent(job.prompt);
return {
status: 200,
content,
feeDeducted: payment.feeAmount + " " + payment.tokenSymbol,
netSettled: payment.netAmount + " " + payment.tokenSymbol,
};
}Agent B: Research Aggregator (Buyer)
Agent B uses raw fetch calls (no SDK) to demonstrate the REST API directly. It requests a service, pays, verifies, and collects the delivery.
const AGENT_A = "http://localhost:4001";
const PAYDIRECT = "http://localhost:3000/api/v1";
const API_KEY = process.env.TEST_API_KEY;
// Step 1: Request content from Agent A
const invoiceRes = await fetch(AGENT_A + "/services/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: "Analyze decentralized payment infrastructure",
buyerAgent: "research-aggregator-v1",
}),
});
const { invoice } = await invoiceRes.json();
// invoice = { paymentId, receivingAddress, amount, tokenSymbol }
// Step 2: In sandbox, payment auto-completes.
// In production, Agent B sends USDC to invoice.receivingAddress on Base.
// Step 3: Verify payment via PayDirect
const verifyRes = await fetch(PAYDIRECT + "/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
body: JSON.stringify({ paymentId: invoice.paymentId }),
});
const { verified } = await verifyRes.json();
// Step 4: Collect delivery
if (verified) {
const deliverRes = await fetch(AGENT_A + "/services/deliver", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ paymentId: invoice.paymentId }),
});
const { content } = await deliverRes.json();
console.log("Content received:", content);
}Running the Demo
The demo ships as two runnable TypeScript scripts. You need a sandbox API key (pd_test_...) and the PayDirect dev server running.
# .env — required variables
TEST_API_KEY=pd_test_your_sandbox_key_here
TEST_BASE_URL=http://localhost:3000/api/v1 # optional, this is the default
AGENT_A_WALLET=0xYourSettlementWalletAddress # any valid 0x address for sandboxpnpm devpnpm demo:agent-a
# Output:
# ========================================================
# Agent A — Content Generator Service
# ========================================================
# Server: http://localhost:4001
# Wallet: 0xYour...
# PayDirect: http://localhost:3000/api/v1
# Mode: SANDBOX
# ========================================================
# Waiting for requests from buyer agents...pnpm demo:agent-b
# Output:
# ========================================================
# Agent B — Content Buyer (research-aggregator-v1)
# ========================================================
#
# [Step 1] Requesting content generation from Agent A...
# Invoice received:
# Payment ID: pay_abc123...
# Amount: 1.00 USDC
# Pay to: 0x...
#
# [Step 2] Processing payment...
# Sandbox mode — payment auto-completed by PayDirect
#
# [Step 3] Verifying payment via PayDirect API...
# Payment verified (attempt 1)
# Gross: 1.00 USDC
# Fee: 0.005 USDC
# Net: 0.995 USDC
#
# [Step 4] Requesting content delivery from Agent A...
#
# ========================================================
# CONTENT DELIVERED SUCCESSFULLY
# ========================================================
# ... generated content ...
# ========================================================
#
# [Done] Agent-to-agent transaction complete.Production Considerations
In production (using pd_live_ keys), sandbox auto-completion is disabled. Agent B must actually send USDC to the receivingAddress on Base mainnet. Use a wallet SDK like Coinbase CDP or viem to execute the transfer:
// Agent B sends USDC to the invoice address (production)
import { createWalletClient, http, parseUnits } from "viem";
import { base } from "viem/chains";
const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
// ERC-20 transfer
const tx = await walletClient.writeContract({
address: USDC_ADDRESS,
abi: erc20Abi,
functionName: "transfer",
args: [invoice.receivingAddress, parseUnits(invoice.amount, 6)],
});Instead of polling /verify, register a webhook to get real-time notifications when payments settle:
// Agent A registers a webhook during startup
await client.createWebhook(
"https://agent-a.example.com/webhooks/paydirect",
["payment.confirmed", "payment.forwarded"]
);
// PayDirect will POST signed events to this URL
// Verify with: PayDirectClient.verifyWebhookSignature(secret, body, sig)Always pass an idempotencyKey when creating payments to prevent duplicate charges if an agent retries a failed request. Use a deterministic key like `${buyerAgent}-${taskId}`.
PayDirect deducts a settlement fee automatically: 0.5% for USDC/ETH, 0.25% for ADAO. The payment.feeAmount and payment.netAmount fields let agents reconcile exact costs. See the Settlement & Fees reference for details.
Next Steps
- Payments API Reference — full endpoint documentation with all parameters.
- Webhooks API Reference — set up real-time payment event notifications.
- SDKs & CLI — TypeScript SDK, Python SDK, and CLI tool reference.
- Use Cases — more scenarios: API monetization, micropayments, subscriptions.
- Testing Guide — run the full API test suite against your integration.
