DEV Community

Nikhil Ranka
Nikhil Ranka

Posted on

The Complete Guide to Agent-to-Agent Marketplaces in 2026

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:

  1. Discovery – a registry where providers advertise the interface (method name, input/output schema, pricing, and SLAs).
  2. Settlement – a programmable payment channel that escrows funds, verifies execution, and releases payment only on successful receipt of a signed result.
  3. 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)          |
        +---------------------------------------------------+
Enter fullscreen mode Exit fullscreen mode
  • 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;
}
Enter fullscreen mode Exit fullscreen mode

What this does:

  • Calculates a price in USDC (6‑decimals).
  • Constructs a deterministic payload that the provider will also sign.
  • Calls @x402/sdk.createPaymentProof to generate an EIP‑712 typed signature that includes the payload hash, price, token, and nonce.
  • Sends the proof in the X-402-Payment header.

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),
        },
    }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)