The Complete Guide to Agent‑to‑Agent Marketplaces in 2026
Autonomous AI agents are now routinely buying and selling capabilities from one another. This guide walks through the architecture, protocols, and pragmatic trade‑offs you need to know if you’re building agents that participate in an A2A marketplace.
1. Why an A2A Marketplace Exists
Agents today are specialized: a perception module, a planner, a language model wrapper, a data‑fetcher, etc. Rather than bake every capability into a monolith, developers expose discrete services (e.g., “summarize‑text‑v2”, “fetch‑weather‑latlon”) and let other agents discover, pay for, and compose them at runtime.
A marketplace provides three core functions:
| Function | What it solves | Typical implementation |
|---|---|---|
| Discovery | Agents need to know what services exist and where to reach them. | Decentralized registry (IPFS‑based manifest) + optional on‑chain index. |
| Pricing & Settlement | Agents must transfer value atomically with service execution. | x402‑style micropayment headers + USDC on Base (or another L2). |
| Trust & Reputation | Agents must verify that a service will behave as advertised. | On‑chain attestations, off‑chain reputation scores, TLS‑mutual auth. |
2. Core Protocol Stack (2026)
| Layer | Protocol | Role | Key Properties |
|---|---|---|---|
| Transport | HTTP/2 + QUIC | Low‑latency, multiplexed request/response. | Works behind NATs, supports server‑push for streaming results. |
| Discovery |
A2A Manifest (JSON‑LD) stored on IPFS, pinned via Filecoin. Agents resolve ipfs://<cid>/manifest.json. |
Immutable, content‑addressed, cheap to read. | |
| Payment | x402 (HTTP 402 Payment Required) with ERC‑20 USDC on Base. | Stateless, pay‑per‑call, no escrow contracts needed. | |
| Identity | DID‑Method: key (did🔑) + Verifiable Credentials for capability claims. | Cryptographic proof of agent identity without a central registry. | |
| Service Description |
MCP‑Lite (Micro‑service Contract Protocol) – a superset of OpenAPI 3.1 with x-payment extensions. |
Defines input/output schemas, pricing, and required auth. | |
| Reputation | On‑chain Registry (ERC‑6551 token‑bound accounts) storing aggregate scores. | Immutable history; can be queried cheaply via RPC. |
Note: The stack is deliberately modular. You can swap IPFS for a centralized CDN if you tolerate censorship risk, or replace USDC with a stablecoin on another L2 if you need different liquidity.
3. Service Discovery in Practice
Agents resolve a manifest via a simple HTTP GET to an IPFS gateway (or a local ipfs node). The manifest lists all services the agent publishes, each with a MCP‑Lite descriptor URL.
// discover.ts – minimal resolver (Node.js ≥18)
import { createHash } from 'crypto';
import { fetch } from 'undici';
const IPFS_GATEWAY = 'https://ipfs.io/ipfs/';
export async function resolveManifest(cid: string) {
const url = `${IPFS_GATEWAY}${cid}/manifest.json`;
const resp = await fetch(url);
if (!resp.ok) throw new Error(`Manifest fetch failed: ${resp.status}`);
return resp.json(); // { services: [{ name, descriptorUrl, priceUsdc }] }
}
// Example usage
(async () => {
const manifest = await resolveManifest('bafybeigdyrzt5wfp7ud7gku7v2kfulza6mnkykakwlwt3e6t2i2jiuowe');
console.log(manifest.services);
})();
Trade‑off: IPFS guarantees immutability but adds ~200‑400 ms latency for a cold read. Pinning services via Filecoin or a dedicated gateway reduces variance but introduces operational cost.
4. Pay‑Per‑Call with x402
When an agent wants to invoke a service, it first sends a probe request without payment. The service replies with 402 Payment Required and an x402-payment-request header containing:
-
scheme:erc20 -
network:base -
token: USDC contract address (0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913) -
amount: micro‑units (1e6 per USDC) -
payload: a nonce + timestamp to prevent replay.
The payer then signs the payload with its private key and resends the request with an x402-payment header.
// x402Client.ts – generic caller using ethers v6
import { ethers } from 'ethers';
import { fetch } from 'undici';
const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const RPC_URL = 'https://base-mainnet.infura.io/v3/<PROJECT_ID>';
const provider = new ethers.JsonRpcProvider(RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
/**
* Calls an x402‑protected endpoint and returns the JSON payload.
* @param url Full URL of the service endpoint.
* @param body Optional JSON‑serializable body (POST) or undefined (GET).
*/
export async function x402Fetch(url: string, body?: any) {
// 1️⃣ Probe
let probe = await fetch(url, {
method: body ? 'POST' : 'GET',
headers: body ? { 'Content-Type': 'application/json' } : {},
...(body && { body: JSON.stringify(body) }),
});
if (probe.status !== 402) {
// No payment required – return directly
const data = await probe.json();
return data;
}
// 2️⃣ Parse payment request
const reqHeader = probe.headers.get('x402-payment-request');
if (!reqHeader) throw new Error('Missing x402-payment-request header');
const { scheme, network, token, amount, payload } = JSON.parse(reqHeader);
if (scheme !== 'erc20' || network !== 'base' || token.toLowerCase() !== USDC_BASE.toLowerCase())
throw new Error('Unsupported payment scheme');
// 3️⃣ Sign the payload (EIP‑191 signed message)
const message = ethers.getBytes(payload);
const signature = await wallet.signMessage(message);
// 4️⃣ Resend with payment header
const paid = await fetch(url, {
method: body ? 'POST' : 'GET',
headers: {
...(body ?body? { 'Content-Type': 'application/json' } : {},
'x402-payment': `${wallet.address}:${signature}`,
},
...(body && { body: JSON.stringify(body) }),
});
if (!paid.ok) throw new Error(`Paid request failed: ${paid.status}`);
return paid.json();
}
// Example: calling a summarizer service
(async () => {
const result = await x402Fetch(
'https://agent-service.example.com/summarize',
{ text: 'The quick brown fox jumps over the lazy dog.', maxLength: 20 }
);
console.log('Summary:', result.summary);
})();
Trade‑offs:
- Statelessness – No need to manage escrow contracts; each call is atomic.
- Latency – Two round‑trips (probe + paid) add ~100‑200 ms on Base.
- Cost – x402 headers add negligible gas; the USDC transfer itself costs ~0.0005 USDC on Base (≈ $0.0005).
5. Describing a Service with MCP‑Lite
An MCP‑Lite document extends OpenAPI with a x-payment object that tells consumers exactly how much to pay and what token to use.
yaml
openapi: 3.1.0
info:
title: Text Summarizer
version: 2.0.0
servers:
- url: https://agent-service.example.com
paths:
/summarize:
post:
summary: Return a concise summary of the supplied text.
operationId: summarize
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [text]
properties:
text:
type: string
description: Input text to summarize.
maxLength:
type: integer
minimum: 10
maximum: 200
default: 60
responses:
'200':
description: Summary result.
content:
application/json:
schema:
type: object
properties:
summary:
type: string
'402':
description: Payment required.
headers:
x402-payment-request:
schema:
type: string
example: |
{"scheme":"erc20","network":"base","token":"0x833589fCD6e
Top comments (0)