x402 Payment Protocol

x402 payment API for pay-per-call access using stablecoins over HTTP. No API keys or subscriptions, just pay and query across chains including Solana.


Beta. x402 access is live on Solana mainnet and Base mainnet. The endpoint surface, pricing tiers, and protocol details may change before general availability — pin the SDK version (@vybenetwork/[email protected]) and watch the npm version history.

What is x402?

x402 is an open protocol from Coinbase that embeds USDC payments directly into HTTP requests using the long-dormant 402 Payment Required status code. Instead of an API key + subscription, a client makes a request, gets a payment prompt, signs a stablecoin transfer, and retries — all within a single HTTP exchange. No accounts, no checkout flow.

The Vybe x402 API exposes the same Vybe endpoints you already use, billed per-call in USDC instead of by subscription. Anyone with a funded wallet on Solana or Base can hit it — humans, scripts, AI agents — without signing up.

  • Base URL: https://x402-api.vybenetwork.xyz (distinct from api.vybenetwork.xyz, the subscription endpoint)
  • Networks: Solana mainnet, Base mainnet — client picks one from the 402 challenge
  • Currency: USDC — EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (Solana mint) or 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 (Base contract)
  • Pricing: $0.003–$0.030 per call, tiered by endpoint

Why pay-per-call?

  • AI agents that need to discover and pay for on-chain data autonomously, without pre-configured API keys.
  • Developers exploring the API who want to try premium endpoints without committing to a plan.
  • Trading bots and scripts that self-fund their data access programmatically.
  • Pay-per-query access to endpoints previously reserved for higher tiers — Top Traders, Wallet PnL, Top Holders, WebSocket streams, etc. — at granular per-request prices.

Setting up a wallet

You need a dedicated wallet with mainnet USDC. The Vybe x402 API covers gas on every payment, so the wallet only needs USDC — no SOL (or ETH) required.

The Vybe SDK below ships with Solana support today. To pay on Base, sign directly against the x402 protocol with @x402/fetch + @x402/evm — see "Without the SDK".

Use a dedicated wallet. Don't point the SDK at a wallet you also use for trading, custody, or anything else. The keypair signs USDC transfers per call; mixing pay-per-call spend with other activity makes bookkeeping fragile and risks unintended charges.

1. Get a keypair. Either:

  • Create one in your existing wallet (Phantom, Solflare, Backpack, …) — add a new account, then "Export Private Key" gives you a base58 string. This is the path most users take.
  • Generate from the CLI — for servers, CI, or anything headless:
    solana-keygen new --no-bip39-passphrase --outfile client.json
    node -e "console.log(Buffer.from(JSON.parse(require('fs').readFileSync('client.json'))).toString('base64'))"

2. Fund it with USDC (mainnet). In order of how most people do it:

  1. Transfer from a wallet you already have — open Phantom/Solflare/Backpack on your main account, send USDC to the new address. Quickest path.
  2. Bridge from another chain if your USDC lives on Ethereum/Base/Arbitrum — Wormhole, deBridge, Phantom's built-in bridge.
  3. Withdraw from a CEX (Coinbase, Kraken, Binance, …) — pick "Solana network" and paste the address.

A few dollars goes a long way given default pricing of $0.003 per call.

3. Wire it up. Set CLIENT_PRIVATE_KEY=<your base58 or base64 string> in your environment.

Quickstart

npm install @vybenetwork/x402-client
import { VybeClient, loadKeypair, ApiError } from "@vybenetwork/x402-client";

const client = new VybeClient({
  wallet: await loadKeypair(process.env.CLIENT_PRIVATE_KEY!),  // base58 or base64
  rpcUrl: process.env.SOLANA_RPC_URL,                          // recommended
  budget: { maxUsd: 1.00, onExceed: "reject" },                // optional cumulative cap
});

// Same paths, params, and response shapes as the regular Vybe API
const token = await client.get("/v4/tokens/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
console.log(token.symbol, token.price);

// POST endpoints work too
const balances = await client.request("/v4/wallets/batch/token-balances", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ ownerAddresses: ["7EK976zyBWhYikjXGASSfN5KoNEekSLqx7wEkUJ8YkHv"] }),
});

The SDK pays the per-call fee on the 402 challenge and returns the parsed body. Same paths and response shapes as the regular Vybe API — the only difference is the base URL: the SDK targets https://x402-api.vybenetwork.xyz (pay-per-call) instead of https://api.vybenetwork.xyz (subscription, API-key auth).

Endpoints

Every endpoint in the Vybe API Reference is callable through the x402 API at the same path. Examples:

  • Token Details — client.get("/v4/tokens/<mintAddress>")
  • Wallet PnL — client.get("/v4/wallets/<ownerAddress>/pnl")
  • Top Holders — client.get("/v4/tokens/<mintAddress>/top-holders")
  • Top Traders — client.get("/v4/wallets/top-traders")
  • Token Balances (batch POST) — client.request("/v4/wallets/batch/token-balances", { method: "POST", body: ... })

Pricing

Per-call, in USDC. $0.003 default, tiered up to $0.030 for the heaviest endpoints. Same dollar amount on Solana or Base — pay on whichever chain you're funded on. Hit GET https://x402-api.vybenetwork.xyz/ for the live, authoritative price table; the SDK reads it on startup so prices aren't hardcoded.

TierPriceExample routes
default$0.003most token/wallet/markets endpoints
30 cr$0.009candles, OHLCV
50 cr$0.015PnL, top-traders, active-users-ts
80 cr$0.024top-holders, transfers, trades, active-users, TVL
100 cr$0.030batch wallet endpoints (POST)
curl https://x402-api.vybenetwork.xyz/
# {
#   "defaultPrice": "$0.003",
#   "pricing": [
#     { "match": "top-holders", "price": "$0.024" },
#     { "match": "pnl",         "price": "$0.015" },
#     ...
#   ]
# }

Safety: spend caps and typed errors

The SDK enforces two complementary spend bounds and surfaces typed errors so agents can react cleanly:

  • maxUsdPerCall (default $0.10) — refuses to sign any 402 challenge demanding more than this amount, before the signature is produced. Defense against API misconfiguration, a 402 injected by a man-in-the-middle, or unexpected price drift.
  • budget.maxUsd — cumulative spend cap across the whole client. Throws BudgetExceededError before signing once the next call would push you over.

Typed errors thrown by the SDK (catch with instanceof):

ErrorWhen
BudgetExceededErrorCall would exceed the cumulative cap. Carries attemptedUsd, capUsd, spentUsd.
UntrustedPaymentErrorPer-call cap exceeded, or 402 mismatch on payTo / network. Thrown before signing — no funds at risk.
PaymentRequiredError402 returned after the signed retry — usually transient (blockhash expired in flight). Retry.
ApiErrorNon-2xx, non-402 status. refunded: true on 5xx (no charge), refunded: false on 4xx (user-error responses still bill).
InsufficientCreditsErrorWebSocket session ran out of credits.
ServiceUnavailableErrorVybe API down. Retry with backoff.
NetworkErrorTransport, DNS, parse failure. Most common cause: client RPC throttled.

WebSocket streaming

Streaming uses the same payment flow as HTTP. One $0.01 payment buys a session of 1000 prepaid credits, the SDK opens a WebSocket, events stream back with credit metadata, and auto-topup fires before credits run out.

const stream = await client.stream({
  filters: { trades: [{ tokenMintAddress: "..." }] },
});
for await (const event of stream) {
  console.log(event.data, "balance:", event.balance);
  if (event.warning === "LOW_BALANCE") console.warn("topping up soon");
}

Filter shapes (same as the regular Vybe WebSocket API):

  • trades — token swap events
  • transfers — SPL token transfers
  • oraclePrices — Pyth oracle updates
  • priceCandles — rolling OHLC bars
  • newToken — new SPL mint creations

Without the SDK

The wire protocol is plain x402 over HTTP plus a small JSON session API for WebSocket. You can build directly against @x402/core + @x402/svm (Solana) or @x402/core + @x402/evm (Base) in any language, or any HTTP client with manual X-PAYMENT header construction.

Pay via Base (EVM)

The Vybe SDK doesn't ship EVM support yet (tracked at vybenetwork/x402-client#2). Until then, pay on Base directly with @x402/fetch + @x402/evm:

import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { toClientEvmSigner } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";

const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const publicClient = createPublicClient({ chain: base, transport: http() });

// `toClientEvmSigner` wraps a viem local account + a public client (used
// for on-chain reads during EIP-3009 signing). Register against the
// Base mainnet network id.
const signer = toClientEvmSigner(account, publicClient);
const client = new x402Client().register("eip155:8453", new ExactEvmScheme(signer));
const fetch402 = wrapFetchWithPayment(fetch, client);

const res = await fetch402("https://x402-api.vybenetwork.xyz/v4/tokens/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const token = await res.json();
console.log(token.symbol, token.price);

Same flow on Base Sepolia for testing — swap basebaseSepolia from viem/chains and eip155:8453eip155:84532. Fund the wallet with testnet USDC at faucet.circle.com (pick "Base Sepolia"). The gateway picks the right chain automatically based on which entry your client signed against.

Pay via Solana

The Vybe SDK above covers this case; under the hood it's @x402/fetch + @x402/svm:

import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactSvmScheme } from "@x402/svm/exact/client";
import { createKeyPairSignerFromBytes } from "@solana/kit";

const keyBytes = Uint8Array.from(Buffer.from(process.env.CLIENT_PRIVATE_KEY!, "base64"));
const signer = await createKeyPairSignerFromBytes(keyBytes);
const client = new x402Client().register(
  "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
  new ExactSvmScheme(signer)
);
const fetch402 = wrapFetchWithPayment(fetch, client);

const res = await fetch402("https://x402-api.vybenetwork.xyz/v4/tokens/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const token = await res.json();
console.log(token.symbol, token.price);

For Solana devnet swap the network id to solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 and fund the wallet via faucet.circle.com (pick "Solana Devnet").

Raw wire protocol

# 1. First call returns 402 with payment requirements (multi-chain)
curl -i https://x402-api.vybenetwork.xyz/v4/tokens/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

# HTTP/2 402
# {
#   "x402Version": 2,
#   "resource": {
#     "url":         "https://x402-api.vybenetwork.xyz/v4/tokens/EPjFWdd5...",
#     "description": "Token Details",
#     "mimeType":    "application/json"
#   },
#   "accepts": [
#     {
#       "scheme":  "exact",
#       "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
#       "amount":  "3000",                                              // 0.003 USDC in atomic units (6 decimals)
#       "asset":   "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",      // Solana USDC mint
#       "payTo":   "HJHe...",
#       "extra":   { "feePayer": "..." }                                // API covers Solana gas
#     },
#     {
#       "scheme":  "exact",
#       "network": "eip155:8453",                                       // Base mainnet
#       "amount":  "3000",
#       "asset":   "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",         // Base USDC contract
#       "payTo":   "0x5a55...",
#       "extra":   { "name": "USD Coin", "version": "2" }               // EIP-712 domain for EIP-3009
#     }
#   ]
# }

# 2. Pick one accepts[] entry, sign a matching USDC transfer with your
#    wallet (SPL transfer on Solana, EIP-3009 transferWithAuthorization
#    on Base), base64-encode the signed x402 payload, and resend with
#    the X-PAYMENT header:
curl -H "X-PAYMENT: <base64-signed-payload>" \
  https://x402-api.vybenetwork.xyz/v4/tokens/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
# → 200 OK + payment-response header (base64 JSON receipt)

The x402 reference implementations cover TypeScript, Go, Python, and Rust. The Vybe SDK is convenience, not protocol.

CLI / MCP without writing code

If you'd rather not add a TypeScript dependency, x402-proxy is a third-party curl-style CLI and MCP proxy that auto-pays any x402 endpoint, including this one:

npx x402-proxy https://x402-api.vybenetwork.xyz/v4/tokens/<mintAddress>

It derives wallet keys from a mnemonic, signs the USDC transfer, retries with the payment header, and streams the response. It also runs as an MCP server, so AI hosts like Claude Desktop, Cursor, or Windsurf can call Vybe endpoints over stdio MCP without our SDK.

FAQ

Do I need an API key?

No. Payment is the authentication. A funded Solana or Base wallet is all you need.

How much SOL/ETH do I need for gas?

Zero. The Vybe x402 API covers transaction fees on every payment, on both Solana and Base. The wallet only needs USDC.

Which chains are supported?

Solana mainnet and Base mainnet today. Same dollar amount per call on either chain. The 402 challenge advertises both — clients pick whichever chain they're funded on. Other EVM chains (Polygon, Arbitrum, World) may be added later without protocol changes.

What endpoints are available?

Every endpoint in the Vybe API Reference is callable through the x402 API at the same path. There's no separate catalog — if it's documented for Vybe, it's payable via x402.

Can I use this without the SDK?

Yes. The wire protocol is plain x402 — see the "Without the SDK" section above. Any language with HTTP and Solana/EVM signing libraries works.

Does the Vybe SDK support Base too?

Not yet — the 0.1.x SDK is Solana-only. EVM/Base support is tracked at vybenetwork/x402-client#2. To pay on Base today, use @x402/fetch + @x402/evm directly per "Without the SDK".

What if a request fails?

Pay-on-success: 5xx responses refund automatically (no charge); 4xx user-error responses still bill (you got a real response). The SDK exposes this via ApiError.refunded and ApiError.chargedUsd.

How do I integrate this with an AI agent?

The SDK has no AI-specific helpers — client.get() / client.request() is the whole interface. Wire any Vybe endpoint into your model's tool-calling loop and dispatch tool calls to the client. The Vybe MCP server also exposes a pay-with-x402 custom tool agents can call for on-demand integration guidance.

Resources

For traditional flat-fee subscription pricing instead of pay-per-call, see vybe.fyi/api-pricing.