docs · complete guide

Build paid APIs for agents, apps, and users.

Verge is an HTTP 402 gateway and SDK. Your server returns a payment challenge, the caller pays on a supported rail, then retries with the transaction proof. Robinhood Chain + USDG is the default; other rails are selected with a single network option.

Overview

What is x402?

A protocol pattern for HTTP 402 Payment Required: request → challenge → payment → retry → access.

Who pays?

Agents, apps, scripts, or humans. The protocol is not agent-only; agents are the strongest use case because they can pay per request automatically.

What does Verge add?

Express/Hono middleware, stablecoin verification, replay protection hooks, wallet console, marketplace listings, API keys, receipts, and a machine-readable catalog.

Install

Pick the adapter for your server framework. Both adapters call the same @vergex402/core verifier.

npm install @vergex402/express
npm install @vergex402/hono hono

Environment you normally need:

WALLET=0xYourRecipientWallet
# optional: overrides the public/default RPC for the selected network
ROBINHOOD_RPC_URL=https://rpc.mainnet.chain.robinhood.com
# optional: used as primary RPC when configured
ALCHEMY_API_KEY=...

Express quickstart

import express from "express";
import { paywall } from "@vergex402/express";

const app = express();
const recipient = process.env.WALLET;
if (!recipient) throw new Error("WALLET is required");

app.use("/api/premium", paywall({
  amount: 0.001,
  recipient,
  network: "robinhood-mainnet", // default rail: USDG on chain 4663
}));

app.get("/api/premium", (_req, res) => {
  res.json({ ok: true, message: "unlocked" });
});

app.listen(3000);

Hono quickstart

import { Hono } from "hono";
import { paywall } from "@vergex402/hono";

const app = new Hono();
const recipient = process.env.WALLET;
if (!recipient) throw new Error("WALLET is required");

app.use("/api/premium", paywall({
  amount: 0.001,
  recipient,
  network: "robinhood-mainnet",
}));

app.get("/api/premium", (c) => c.json({ ok: true, message: "unlocked" }));

The x402 request flow

  1. 1. Caller requests a protected route. Without proof, Verge returns HTTP 402 with both wire formats: the x402 v2 PAYMENT-REQUIRED header (base64 JSON) and the legacy X-Pay-* headers.
  2. 2. Caller pays the requested asset. The challenge includes amount, recipient, network (CAIP-2 in the v2 header), token reference, and nonce.
  3. 3. Caller retries with proof. Standard agents send PAYMENT-SIGNATURE (base64 PaymentPayload with the settlement tx); Verge-native callers can send X-Pay-Tx + X-Pay-Nonce.
  4. 4. Middleware verifies settlement. EVM rails check stablecoin Transfer logs; Solana and Sui use their own transaction/balance verification paths.
curl -i http://localhost:3000/api/premium

HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Mi4uLg==  (base64 of:)
{ "x402Version": 2, "resource": { "url": "..." },
  "accepts": [{ "scheme": "exact", "network": "eip155:4663",
    "amount": "1000", "asset": "0x5fc5...d168", "payTo": "0x...",
    "maxTimeoutSeconds": 600, "extra": { "paymentFlow": "upfront",
    "nonce": "8f3c2d" } }],
  "extensions": { "x-verge": { "info": { "nonce": "8f3c2d" } } } }
WWW-Authenticate: x402 realm="verge", nonce="8f3c2d", amount="0.001", recipient="0x...", network="robinhood-mainnet"
X-Pay-Token: USDG
X-Pay-Network: robinhood-mainnet
X-Pay-Chain-Id: 4663
X-Pay-Amount: 0.001
X-Pay-Recipient: 0x...
X-Pay-Nonce: 8f3c2d
# Standard x402 v2 agent style:
curl -i http://localhost:3000/api/premium \
  -H "PAYMENT-SIGNATURE: <base64 of PaymentPayload JSON>
   { x402Version: 2, accepted: { scheme: exact, network: eip155:4663 },
     payload: { tx: 0xYourSettlementTx, nonce: 8f3c2d } }"

# Verge-native style (equivalent):
curl -i http://localhost:3000/api/premium \
  -H "X-Pay-Tx: 0xYourSettlementTx" \
  -H "X-Pay-Nonce: 8f3c2d"

HTTP/1.1 200 OK
{ "ok": true, "message": "unlocked" }

Facilitator API (hosted)

Vergesnowy.com runs a public x402 v2 facilitator. Any resource server — including your paywall() middleware — can delegate verification and settlement commitment to it, the same role Coinbase CDP or thirdweb facilitators play, but for Robinhood Chain USDG plus six more rails. Zero protocol fees.

curl https://vergesnowy.com/api/facilitator/supported

{ "kinds": [ { "x402Version": 2, "scheme": "exact",
    "network": "eip155:4663" }, "..." ],
  "extensions": ["x-verge"] }

# Read-only check (spec 7.1):
curl -X POST https://vergesnowy.com/api/facilitator/verify \
  -H "content-type: application/json" \
  -d '{ "x402Version": 2,
        "paymentPayload": { "payload": { "tx": "0x...", "nonce": "..." } },
        "paymentRequirements": { "scheme": "exact", "network": "eip155:4663",
          "amount": "1000", "asset": "0x5fc5...d168", "payTo": "0x..." } }

{ "isValid": true, "payer": "0x..." }

# Commit settlement (spec 7.2) - consumes the nonce, blocks replay:
curl -X POST https://vergesnowy.com/api/facilitator/settle -d "...same body..."

Client retry helper

A caller does not need a Verge account. It only needs to understand the 402 response, pay the requested rail, then retry with the proof headers. The core package now exports helpers for parsing the challenge and building retry headers.

import { parseX402Authenticate, paymentProofHeaders } from "@vergex402/core";

const first = await fetch("https://api.example.com/premium");
if (first.status === 402) {
  const challenge = parseX402Authenticate(first.headers.get("www-authenticate") || "");
  // Your wallet/payment engine sends challenge.amount to challenge.recipient
  // on challenge.network, then returns the settlement transaction hash.
  const txHash = await payStablecoin(challenge);

  const unlocked = await fetch("https://api.example.com/premium", {
    headers: paymentProofHeaders(txHash, challenge.nonce),
  });
}

Security model

Issued nonce required

A paid retry must present a nonce that the middleware actually issued. Unknown or already-consumed nonces return NONCE_INVALID.

Replay-safe transaction hashes

Each tx hash is keyed by network and rejected after the first successful unlock. Use a durable ReplayStore in multi-process production.

Settlement verification

EVM rails inspect stablecoin Transfer logs; Solana inspects SPL token-balance deltas; Sui inspects finalized balance changes.

Stateless option

The built-in stores are in-memory for simple servers. Bring Redis/Postgres stores when running multiple workers or serverless replicas.

Multichain: one option, not a different command

You were right to ask: every chain has its own identifier, token, verifier path, and RPC. In Verge, you do not run a different command for each chain. You set network in the SDK options. If omitted, Verge uses robinhood-mainnet. The 402 response tells the caller which network, token, recipient, amount, and nonce to use.

Network stringChainChain IDAssetNotes
robinhood-mainnetRobinhood Chain4663USDGDefault / flagship rail
ethereum-mainnetEthereum1USDCExplicit opt-in EVM rail
base-mainnetBase8453USDCExplicit opt-in EVM rail
arbitrum-mainnetArbitrum One42161USDCExplicit opt-in EVM rail
polygon-mainnetPolygon137USDCExplicit opt-in EVM rail
solana-mainnetSolanaSVMUSDCExplicit opt-in SVM rail
sui-mainnetSuiMoveUSDCExplicit opt-in Move rail
app.use("/api/premium", paywall({
  amount: 0.001,
  recipient,
  network: "base-mainnet", // or ethereum-mainnet, arbitrum-mainnet, polygon-mainnet, solana-mainnet, sui-mainnet
}));

Current app reality: the public catalog shows all supported rails; private wallet balances and transaction history in the console are Robinhood Chain-focused today.

AI SDK middleware

Use @vergex402/ai-sdk to wrap any Vercel AI SDK model or gate your own AI routes with per-call USDG payments.

npm install @vergex402/ai-sdk @vergex402/fetch

Client — pay to call a gated model endpoint

import { wrapWith402 } from "@vergex402/ai-sdk";
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";

const model = wrapWith402(openai("gpt-4o-mini"), {
  endpoint: "https://your-api.com/api/ai",
  privateKey: process.env.AGENT_KEY as `0x${string}`,
  maxAmountUsdg: 0.01,
});
const { text } = await generateText({ model, prompt: "Hello" });

Server — monetize your AI route (Next.js)

import { createX402Gate } from "@vergex402/ai-sdk";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";

const { POST: gateCheck } = createX402Gate({
  amount: 0.001,   // USDG per call
  recipient: "0xYOUR_WALLET",
});

export async function POST(req: Request) {
  const gateRes = await gateCheck(req.clone());
  if (gateRes.status === 402) return gateRes;  // sends PAYMENT-REQUIRED
  const { messages } = await req.json();
  return streamText({ model: openai("gpt-4o-mini"), messages }).toDataStreamResponse();
}

MCP server

Verge exposes an MCP-over-HTTP server at /api/mcp that any AI agent (Claude, Cursor, ChatGPT) can use as a tool server.

Add to Claude Code / Cursor

# In your MCP config (claude_desktop_config.json or .cursor/mcp.json):
{
  "mcpServers": {
    "verge": {
      "url": "https://vergesnowy.com/api/mcp",
      "transport": "http"
    }
  }
}

Available tools: inspect_endpoint, list_marketplace, create_invoice, get_reputation

Inspect tools endpoint →

@vergex402/fetch — buyer SDK

The fetch SDK is for agents or scripts that need to pay for x402-gated endpoints. It handles the full challenge-sign-retry loop automatically.

npm install @vergex402/fetch viem
import { payAndFetch } from "@vergex402/fetch";

const res = await payAndFetch("https://vergesnowy.com/x/crypto-price", {
  privateKey: process.env.AGENT_KEY as `0x${string}`,
  maxAmount: 0.01,  // USDG ceiling — throws if challenge > this
});
const data = await res.json();

Revenue splits

Automatically distribute incoming USDG to multiple wallets. Configure splits in basis points (10,000 = 100%). Applied on every facilitator settlement.

// POST /api/splits — create a split rule
fetch("/api/splits", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    recipient: "0xCOFOUNDER_WALLET",
    basisPoints: 2000,  // 20%
    label: "Co-founder share",
  }),
});

// GET /api/splits — list all splits for connected wallet
// DELETE /api/splits?id=spl_xxx — remove a split rule

Splits are enforced server-side at settlement. Max 10 recipients per wallet, sum ≤ 10,000 bps.

Developer portal / console

The console is the user-facing workspace. Visitors can explore payment rails and the marketplace before connecting. Wallet connection is only required for private actions.

Overview: wallet balance, endpoint count, paid calls, settlement volume
Transactions: confirmed incoming stablecoin transfers
Marketplace: browse and publish paid endpoints
Receipts: explorer-linked settlement proofs
API Keys: create/revoke wallet-scoped credentials
Networks: rail registry, token reference, explorer links, SDK snippets

API keys

API keys are for apps that want Verge-managed access without forcing every request to carry a payment transaction. A wallet signs into the console, creates a key, and your server can introspect it.

curl -X POST https://vergesnowy.com/api/keys/verify   -H "content-type: application/json"   -d '{"key": "vg_live_..."}'

{ "ok": true, "wallet": "0xabc...", "remaining": 998, "limit": 1000 }

Introspection reports validity, revocation state, and remaining quota. Unknown, revoked, or exhausted keys return HTTP 401.

Marketplace and catalog

The marketplace is the human UI for paid endpoints. /api/catalog is the machine-readable version for agents and crawlers. Use it to discover endpoints, supported rails, docs URL, gateway URL, and demo routes.

curl https://vergesnowy.com/api/catalog
curl https://vergesnowy.com/api/marketplace
curl https://vergesnowy.com/api/demo

Reference