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

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

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

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

Top comments (0)