The Complete Guide to Agent-to-Agent Marketplaces in 2026
Introduction
Agent‑to‑agent (A2A) marketplaces have moved from experimental prototypes to a production‑grade layer for autonomous software. In 2026 the ecosystem is defined by three concrete realities:
- Standardized payment – the x402 protocol is the de‑facto way to attach a verifiable, micro‑transaction fee to every request.
- Identity & trust – Decentralized Identifiers (DIDs) coupled with Verifiable Credentials (VCs) let agents prove who they are and what capabilities they expose without a central registry.
- Service discovery – Catalogs are immutable, often hosted on IPFS or a lightweight Worker‑based gateway, and indexed by capability hashes rather than human‑readable names.
This guide walks through the moving parts, shows working code for both consuming and providing services, and outlines the trade‑offs you’ll face when you build on top of this stack.
Core Architecture
+-------------------+ x402 request (USDC on Base) +-------------------+
| Consumer Agent | <----------------------------------> | Provider Agent |
| (DID: did:example) | Header: X-402-Payment: <signed> | (DID: did:svc:…) |
+-------------------+ +-------------------+
| |
| HTTP/2 (or QUIC) |
v v
+-------------------+ +-------------------+
| Discovery Layer | (IPFS pin / Worker catalog) | Execution Env |
| (capability hash) | (sandbox, WASM) |
+-------------------+ +-------------------+
- Consumer Agent – creates an x402 payment payload, signs it with its DID key, and sends it as an HTTP header.
- Provider Agent – validates the payment, checks the consumer’s DID against any required VC (e.g., “licensed to call financial APIs”), then runs the encapsulated logic.
- Discovery Layer – stores a JSON‑LD document that maps a capability hash (SHA‑256 of the service’s input/output schema) to an endpoint URL and price. No human‑readable names are required; agents resolve by hash.
The stack is deliberately minimal: no message brokers, no long‑lived sessions, and no mandatory middleware. This keeps latency low but pushes reliability concerns (retries, idempotency) onto the agents themselves.
Standards You’ll Need to Know
| Standard | Purpose | Current Status (2026) |
|---|---|---|
| x402 (IETF draft) | Attach a verifiable, micro‑payment to HTTP requests. Uses USDC on Base L2; payment proof is a signed EIP‑712 message. | Implemented in most HTTP libraries; widely adopted for paid APIs. |
| DID Method: key | Lightweight, controller‑managed identifier. No blockchain write needed for creation. | Supported by did-js, did-py. |
| Verifiable Credentials (VC-JWT) | Express capabilities, licenses, or reputation. Verified against the issuer’s DID document. | Standard library support; issuers include OpenCredentials.org. |
| Capability Hash (SHA‑256 of JSON‑Schema) | Immutable identifier for a service’s contract. Enables caching and reduces naming collisions. | Used by the NexusAI catalog and most private registries. |
| IPFS / Filecoin Pinning | Host the discovery document so it cannot be altered without changing its CID. | Pinning services offer SLA‑backed guarantees; cost ~ $0.0005/GB/month. |
You do not need to implement all of these from scratch; mature SDKs exist for each.
Consuming a Service: Working Code Snippet
The following Python example shows how a consumer agent:
- Loads its DID key.
- Builds an x402 payment for a service priced at 0.05 USDC.
- Adds the payment header and a VC proving it holds a “data‑analysis” license.
- Calls the endpoint and handles the response.
# consumer.py
import json
import time
import requests
from eth_account import Account
from eth_account.messages import encode_typed_data
from didkit import key_to_did, did_resolve
from vc import VerifiableCredential # hypothetical helper
# 1. Load consumer DID (key method)
PRIVATE_KEY = "0xabcd..." # keep in env or secret manager
acct = Account.from_key(PRIVATE_KEY)
DID = f"did:key:{acct.address}"
print(f"Consumer DID: {DID}")
# 2. Prepare x402 payment (EIP-712 typed data)
def build_x402_payment(amount_usdc: float, endpoint: str, nonce: int):
# USDC on Base has 6 decimals
amount_wei = int(amount_usdc * 1_000_000)
domain = {
"name": "x402",
"version": "1",
"chainId": 8453, # Base
"verifyingContract": "0x0000000000000000000000000000000000000000" # placeholder
}
types = {
"EIP712Domain": [
{"name": "name", "type": "string"},
{"name": "version", "type": "string"},
{"name": "chainId", "type": "uint256"},
{"name": "verifyingContract", "type": "address"}
],
"Payment": [
{"name": "receiver", "type": "address"},
{"name": "amount", "type": "uint256"},
{"name": "nonce", "type": "uint256"},
{"name": "target", "type": "string"}
]
}
message = {
"receiver": "0x1111111111111111111111111111111111111111", # provider address (known off‑chain)
"amount": amount_wei,
"nonce": nonce,
"target": endpoint
}
typed_data = {"types": types, "domain": domain, "primaryType": "Payment", "message": message}
signed = Account.sign_typed_data(DID.split(":")[-1], typed_message=typed_data)
return signed.signature.hex()
# 3. Load a VC that proves the consumer is allowed to call data‑analysis services
vc = VerifiableCredential.from_json(open("analysis_license.vc"))
vc_jwt = vc.to_jwt(acct) # signs with consumer key
# 4. Call the service
endpoint = "https://agent-service.example.com/analyze"
nonce = int(time.time())
payment_sig = build_x402_payment(0.05, endpoint, nonce)
headers = {
"Content-Type": "application/json",
"X-402-Payment": f"{payment_sig}.{nonce}", # format: signature.nonce
"Authorization": f"Bearer {vc_jwt}"
}
payload = {"data": [1, 2, 3, 4, 5]}
resp = requests.post(endpoint, headers=headers, json=payload, timeout=10)
resp.raise_for_status()
print("Result:", resp.json())
What this snippet demonstrates
- Payment construction follows the x402 spec; the provider will recover the signer address from the signature and verify the nonce hasn’t been reused.
- The VC is sent as a Bearer token; the provider can verify it against the issuer’s DID document.
- No external SDK is required beyond
eth-accountand a minimal DID helper—showing the low barrier to entry.
Providing a Service: Working Code Snippet
A provider agent must:
- Verify the x402 payment.
- Validate any presented VC against a policy (e.g., only holders of a specific license may call).
- Execute the core logic in a sandbox (WASM in this example) and return the result.
rust
// provider.rs (using actix-web and the x402‑verify crate)
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use x402::verify_payment; // hypothetical crate that checks signature, nonce, replay
use didkit::{resolve_did, verify_vc}; // DID and VC helpers
use wasmtime::{Engine, Store, Module, Instance};
#[derive(Deserialize)]
struct AnalyzeReq {
data: Vec<f64>,
}
#[derive(Serialize)]
struct AnalyzeResp {
mean: f64,
sum: f64,
}
/*
* WASM module that exports a `analyze` function:
* (ptr len) -> (ptr len) returning a JSON blob.
* For brevity we assume the module is pre‑compiled and bundled.
*/
const WASM_BY
Top comments (0)