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 build autonomous AI agents and need to integrate paid, discoverable services from other agents.


1. Why Agent‑to‑Agent Marketplaces Matter

By 2026 most non‑trivial AI workflows consist of multiple specialized agents—perception, planning, tool‑use, and post‑processing—each potentially owned by a different party. Direct point‑to‑point integrations are brittle: version drift, authentication mismatches, and ad‑hoc pricing negotiations increase operational overhead. A marketplace layer solves three problems:

  1. Discovery – agents can publish a machine‑readable descriptor of what they do, input/output schemas, and price.
  2. Settlement – micropayments are handled atomically, eliminating invoicing delays.
  3. Governance – reputation scores and SLAs are visible before a call is made.

The trade‑off is added latency (an extra hop through a registry or gateway) and the need to adopt a shared protocol. The following sections walk through a concrete implementation that has seen production use in several open‑source agent frameworks.


2. Core Architecture

+----------------+        HTTP/JSON‑RPC        +----------------+
|  Agent A       | <------------------------> |  Registry      |
| (consumer)     |  discover / call           | (x402‑enabled)  |
+----------------+        +----------------    +----------------+
                         |   Gateway (relay)   |
                         +---------------------+
                                  |
                         HTTP/JSON‑RPC (x402)
                                  |
                         +----------------+
                         |  Agent B       |
                         | (provider)     |
                         +----------------+
Enter fullscreen mode Exit fullscreen mode
  • Registry – a static JSON file or a decentralized identifier (DID) document that maps a service ID to an endpoint, schema, and price.
  • Gateway – optional thin proxy that enforces payment verification before forwarding the request to the provider. It can also add rate‑limiting and logging.
  • Agent B – implements the actual capability and returns a signed receipt (see §4).

All communication uses JSON‑RPC 2.0 over HTTP/2. The only deviation from vanilla RPC is the inclusion of an x402 payment header that carries a signed payment request and, on the response side, a receipt.


3. Service Descriptor (Discovery)

Agents publish a descriptor at a well‑known path, e.g., /.well-known/agent-service.json. The format is deliberately minimal to keep parsing cheap.

{
  "$schema": "https://schemastore.azurewebsites.net/schemas/json/agent-service-v1.json",
  "serviceId": "agent::weather::forecast/v2",
  "displayName": "Hourly Weather Forecast",
  "description": "Returns temperature, precipitation, and wind for a given lat/lon and timestamp.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "lat": { "type": "number", "minimum": -90, "maximum": 90 },
      "lon": { "type": "number", "minimum": -180, "maximum": 180 },
      "ts":  { "type": "string", "format": "date-time" }
    },
    "required": ["lat", "lon", "ts"]
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "tempC": { "type": "number" },
      "precipMm": { "type": "number", "minimum": 0 },
      "windKmh": { "type": "number", "minimum": 0 }
    },
    "required": ["tempC", "precipMm", "windKmh"]
  },
  "price": {
    "currency": "USDC",
    "network": "Base",
    "amount": "0.03"
  },
  "endpoint": "https://weather-agent.example.com/rpc",
  "providerDid": "did:key:z6Mkr...",
  "signature": "0xabc123..."
}
Enter fullscreen mode Exit fullscreen mode

The signature field is a JWS over the canonical JSON (excluding the signature itself) using the provider’s DID key. Consumers verify it before trusting the descriptor.


4. Micropayment Flow with x402

The x402 specification defines two HTTP headers:

  • X-402-Payment-Required – returned by the gateway when no valid payment is present. It contains a payment request (amount, network, token, and a nonce).
  • X-402-Payment – sent by the consumer, containing a signed payment that satisfies the request.

4.1 Consumer Side (Python‑like pseudocode)

import json, requests, eth_account
from eth_account.messages import encode_defunct

REGISTRY_URL = "https://registry.example.com/.well-known/agent-service.json"
AGENT_RPC = None
PRICE_USDC = None
NONCE = None

def fetch_descriptor():
    r = requests.get(REGISTRY_URL, timeout=5)
    r.raise_for_status()
    return r.json()

def sign_payment(amount_usdc, nonce, privkey):
    # x402 expects a signed message: "<amount> USDC <nonce>"
    message = f"{amount_usdc} USDC {nonce}"
    encoded = encode_defunct(text=message)
    signed = eth_account.Account.sign_message(encoded, privkey)
    return signed.signature.hex()

def call_agent(method, params, privkey):
    global AGENT_RPC, PRICE_USDC, NONCE
    payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": 1
    }
    headers = {"Content-Type": "application/json"}
    resp = requests.post(AGENT_RPC, json=payload, headers=headers, timeout=10)
    # If we get a 402, we need to pay
    if resp.status_code == 402:
        # Extract payment request from header
        req = resp.headers["X-402-Payment-Required"]
        req_json = json.loads(req)
        PRICE_USDC = req_json["amount"]
        NONCE = req_json["nonce"]
        signature = sign_payment(PRICE_USDC, NONCE, privkey)
        pay_header = {
            "X-402-Payment": json.dumps({
                "amount": PRICE_USDC,
                "nonce": NONCE,
                "signature": signature,
                "token": "USDC",
                "network": "Base"
            })
        }
        headers.update(pay_header)
        resp = requests.post(AGENT_RPC, json=payload, headers=headers, timeout=10)
    resp.raise_for_status()
    return resp.json()["result"]

# --- usage ---
desc = fetch_descriptor()
AGENT_RPC = desc["endpoint"]
PRICE_USDC = desc["price"]["amount"]  # optional pre‑fetch
# In practice you would load a private key from a vault or env var
PRIVATE_KEY = "0xYourPrivateKey..."
result = call_agent("weather.forecast", {"lat": 37.77, "lon": -122.41, "ts": "2026-09-24T12:00:00Z"}, PRIVATE_KEY)
print(result)
Enter fullscreen mode Exit fullscreen mode

What the code does:

  1. Pulls the service descriptor from a public registry.
  2. Attempts a plain JSON‑RPC call.
  3. On a 402 response, extracts the payment request, signs it with the consumer’s Ethereum‑compatible private key (the same key can be used for USDC on Base via the ERC‑20 contract), and retries.
  4. Returns the agent’s result if the payment settles.

4.2 Provider Side (minimal Express‑like handler)


javascript
const express = require('express');
const { verify } = require('eth-sig-util');
const { bufferToHex } = require('ethereumjs-util');
const app = express();
app.use(express.json());

const SERVICE_PRICE = "0.03"; // USDC
const USDC_CONTRACT = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; // Base USDC

function verifyPayment(req) {
  const payHeader = req.headers['x-402-payment'];
  if (!payHeader) return false;
  const { amount, nonce, signature, token, network } = JSON.parse(payHeader);
  if (token !== USDC_CONTRACT || network !== 'Base' || amount !== SERVICE_PRICE) return false;
  const msg = `${amount} USDC ${nonce}`;
  const msgBuffer = Buffer.from(msg);
  const addr = verify({
    msg: msgBuffer,
    sig: signature
  });
  // In production you would also check that the sender actually transferred USDC
  // via a lightweight escrow contract or by querying an indexer.
  return addr.toLowerCase();
}

app.post('/rpc', (req, res) => {
  if (!verifyPayment(req)) {
    res.set('X-402-Payment-Required', JSON.stringify({
      amount: SERVICE_PRICE,
      token: USDC_CONTRACT,
      network: 'Base',
      nonce: Math.random().toString(36).substring(2, 10)
    }));
    return
Enter fullscreen mode Exit fullscreen mode

Top comments (0)