In 2026, the primary consumers of web APIs are no longer human-facing frontend applications. They are autonomous AI agents.
When Agent $A$ needs to solve a sub-task outside its domain—such as verifying a zk-proof, deep-scanning a smart contract, or running a highly specialized forecasting model—it does not wait for a human developer to integrate a new API. It discovers, negotiates with, and pays Agent $B$ dynamically.
This shift has birthed Agent-to-Agent (A2A) Marketplaces. This guide breaks down the core technical architecture of these marketplaces, details a production-grade integration pattern, and discusses the engineering trade-offs you will face when building for the machine-to-machine (M2M) economy.
A standardized A2A interaction bypasses traditional OAuth flows, credit card checkouts, and interactive API documentation. Instead, it relies on three pillars:
/.well-known/agent.json)
+-------------+ +-------------------+ +--------------+
| | -- 1. Discover ->| Agent Registry | | |
| Consumer | <--- Metadata --+ + | Provider |
| Agent | | Agent |
| | ------------------ 2. POST /quote ------------------> | |
| | <----------------- 3. Invoice Hash & Fee -------------| |
| | ------------------ 4. Execute Payment (L2) --------->| |
| | ------------------ 5. POST /execute + Tx Proof -----> | |
| | <----------------- 6. Signed Execution Result --------| |
+-------------+ +--------------+
Below is a complete Node.js/TypeScript implementation demonstrating how an autonomous consumer agent dynamically discovers an endpoint, requests an execution quote, settles the payment using USDC on the Base network, and verifies the signed execution payload.
typescript
import { ethers } from "ethers";
interface AgentServiceMetadata {
endpoint: string;
paymentAddress: string;
supportedTokens: string[];
}
interface ServiceQuote {
quoteId: string;
feeInUSDC: string; // Base units (6 decimals)
expiresAt: number;
}
interface ExecutionResult {
output: string;
signature: string;
}
class AgentConsumerClient {
private wallet: ethers.Wallet;
private usdcContract: ethers.Contract;
constructor(privateKey: string, providerUrl: string, usdcAddress: string) {
const provider = new ethers.JsonRpcProvider(providerUrl);
this.wallet = new ethers.Wallet(privateKey, provider);
// ERC-20 Minimal ABI
const minABI = [
"function transfer(address to, uint256 value) external returns (bool)",
];
this.usdcContract = new ethers.Contract(usdcAddress, minABI, this.wallet);
}
// Step 1: Discover Agent Metadata
async discoverAgent(url: string): Promise<AgentServiceMetadata> {
const res = await fetch(`${url}/.well-known/agent.json`);
if (!res.ok) throw new Error("Failed to fetch agent metadata");
return res.json() as Promise<AgentServiceMetadata>;
}
// Step 2: Request Quote for a Specific Prompt
async getQuote(endpoint: string, taskPayload: object): Promise<ServiceQuote> {
const res = await fetch(`${endpoint}/quote`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(taskPayload),
});
if (!res.ok) throw new Error("Failed to obtain pricing quote");
return res.json() as Promise<ServiceQuote>;
}
// Step 3 & 4: Settle Payment & Request Execution
async executeTask(
metadata: AgentServiceMetadata,
quote: ServiceQuote,
taskPayload: object
): Promise<ExecutionResult> {
console.log(`Settling payment of ${ethers.formatUnits(quote