The Complete Guide to Agent-to-Agent Marketplaces in 2026
Target audience: developers who are building autonomous AI agents and need to integrate paid, on‑demand services from other agents.
1. What an Agent‑to‑Agent (A2A) Marketplace Really Is
An A2A marketplace is a decentralized service‑discovery and settlement layer that lets one autonomous agent invoke another agent’s capability as a remote procedure call (RPC). Unlike traditional API gateways, the counterparty is not a static SaaS endpoint but a software entity that may be spun up, versioned, or retired on‑the‑fly by its owner. The marketplace supplies three core primitives:
- Discovery – a registry where providers advertise the interface (method name, input/output schema, pricing, and SLAs).
- Settlement – a programmable payment channel that escrows funds, verifies execution, and releases payment only on successful receipt of a signed result.
- Guarantees – optional reputation or attestation data that lets consumers assess reliability before committing funds.
In 2026 the dominant settlement standard is x402, a blockchain‑native micro‑payment protocol that works over HTTP and uses ERC‑20 tokens (most commonly USDC on Base). x402 replaces API keys with a cryptographic proof‑of‑payment that the consumer includes in the request header; the provider validates the proof before processing the call.
2. Architectural Overview
+----------------+ x402 payment proof +----------------+
| Consumer Agent | ----------------------------> | Provider Agent |
| (off‑chain) | <--------------------------- | (off‑chain) |
+----------------+ signed result + receipt +----------------+
^ ^
| |
| Registry (IPFS/Filecoin or chain‑based) |
+---------------------------------------------------+
- Consumer Agent – builds an HTTP request, attaches an x402 payment proof, sends it to the provider’s endpoint, and validates the signed response.
- Provider Agent – runs a lightweight HTTP server, checks the x402 header, executes its internal logic, signs the payload (often with an EIP‑712 typed structure), and returns the signature plus the raw result.
- Registry – stores service metadata. It can be a simple JSON file pinned to IPFS, a smart contract mapping service IDs to metadata, or a hybrid approach. The registry does not handle payment; it only aids discovery.
3. Working with x402
3.1 Consumer side (TypeScript / Node)
import { createPaymentProof } from '@x402/sdk';
import axios from 'axios';
import { ethers } from 'ethers';
// USDC on Base (address: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913)
const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const PRIVATE_KEY = process.env.PRIVATE_KEY!; // consumer's EOA
const provider = new ethers.JsonRpcProvider('https://base.mainnet.rpc.cloud');
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
// Example: calling a text‑summarization agent
async function callSummarizer(text: string) {
const price = ethers.parseUnits('0.05', 6); // $0.05 USDC = 50,000 USDC (6 decimals)
const nonce = Date.now(); // simple nonce; in production use a monotonic counter
const payload = ethers.solidityPacked(
['address', 'uint256', 'uint256', 'string'],
[USDC, price, nonce, text]
);
// Create x402 proof: signs (method, price, token, nonce, bodyHash)
const proof = await createPaymentProof({
payer: wallet.address,
payee: '0xProviderAgentAddress', // replace with actual provider
token: USDC,
amount: price,
nonce,
body: text, // the provider will hash this internally
signer: wallet,
});
const resp = await axios.post(
'https://agent.summarize.example.com/v1/summarize',
{ text },
{
headers: {
'Content-Type': 'application/json',
'X-402-Payment': JSON.stringify(proof),
},
}
);
// Provider returns { result, signature }
const { result, signature } = resp.data;
// Verify signature (EIP‑712) – omitted for brevity
return result;
}
What this does:
- Calculates a price in USDC (6‑decimals).
- Constructs a deterministic payload that the provider will also sign.
- Calls
@x402/sdk.createPaymentProofto generate an EIP‑712 typed signature that includes the payload hash, price, token, and nonce. - Sends the proof in the
X-402-Paymentheader.
3.2 Provider side (Python / FastAPI)
python
import os
import hashlib
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
from eth_account.messages import encode_defunct
from eth_account import Account
app = FastAPI()
PROVIDER_KEY = os.getenv('PROVIDER_PRIVATE_KEY')
PROVIDER_ADDR = Account.from_key(PROVIDER_KEY).address
class SummarizeReq(BaseModel):
text: str
class X402Proof(BaseModel):
payer: str
payee: str
token: str
amount: int # uint256
nonce: int
# v, r, s components of the signature
v: int
r: str
s: str
def verify_x402(proof: X402Proof, body: bytes) -> bool:
# Recreate the signed message: keccak256(
// 0x19, 0x01,
// domainSeparator,
// keccak256(encode(
// address payer,
// address payee,
// address token,
// uint256 amount,
// uint256 nonce,
// bytes32 bodyHash
// ))
// )
domain_separator = bytes.fromhex(
"0000000000000000000000000000000000000000000000000000000000000001"
) # placeholder; real implementation uses EIP‑712 domain
body_hash = hashlib.sha256(body).digest()
encoded = (
proof.payer.lower()
+ proof.payee.lower()
+ proof.token.lower()
+ proof.amount.to_bytes(32, "big").hex()
+ proof.nonce.to_bytes(32, "big").hex()
+ body_hash.hex()
)
msg_hash = hashlib.sha256(
bytes.fromhex("1901") + domain_separator + hashlib.sha256(bytes.fromhex(encoded)).digest()
).digest()
eth_msg = encode_defunct(msg_hash)
recovered = Account.recover_message(eth_msg, vrs=(proof.v, proof.r, proof.s))
return recovered.lower() == PROVIDER_ADDR.lower()
@app.post("/v1/summarize")
async def summarize(
req: SummarizeReq,
x402_payment: str = Header(None),
):
if not x402_payment:
raise HTTPException(status_code=402, detail="Missing X-402-Payment header")
proof = X402Proof.model_validate_json(x402_payment)
if not verify_x402(proof, req.text.encode()):
raise HTTPException(status_code=402, detail="Invalid payment proof")
# ---- Business logic ----
# (here we could call a local LLM or another micro‑service)
summary = req.text[:100] + "…" # stub
# Sign the result (EIP‑712) so consumer can verify authenticity
result_body = {"summary": summary}
result_bytes = json.dumps(result_body, separators=(",", ":")).encode()
# Build typed data for signing (simplified)
# In practice use eip712-structs library
domain = {
"name": "SummarizerAgent",
"version": "1",
"chainId": 8453, # Base
"verifyingContract": PROVIDER_ADDR,
}
types = {
"Result": [
{"name": "summary", "type": "string"},
],
}
message = {"summary": summary}
eth_typed_data = encode_typed_data(domain, types, message)
signed_account = Account.from_key(PROVIDER_KEY)
eth_msg = encode_defunct(eth_typed_data)
sig = signed_account.sign_message(eth_msg)
return {
"result": result_body,
"signature": {
"v": sig.v,
"r": hex(sig.r),
"s": hex(sig.s),
},
}
Top comments (0)