Three npm packages, a Solana wallet with USDC, and you’re querying smart money data across Polymarket, Hyperliquid, and Meteora. The entire flow is gasless — no SOL required.
What You Need
- Solana wallet with USDC (that’s it — x402 is gasless, no SOL needed)
- Node.js 18+ or Bun runtime
- Three packages:
npm install @x402/core @x402/svm @solana/kit
How x402 Works
The x402 protocol turns HTTP 402 (“Payment Required”) into a machine-readable payment flow. No API keys, no accounts. Your wallet is your identity.
First Request Returns 402
You call an endpoint. The server responds with HTTP 402 and a PAYMENT-REQUIRED header containing the exact USDC price and payment instructions.
Sign Payment Locally
Your agent parses the payment requirement, signs a USDC transfer with your Solana keypair, and builds a payment signature. No funds move yet.
Re-send With Payment
Attach the PAYMENT-SIGNATURE header and re-send the same request. The server verifies the signature, settles the payment on-chain, and returns your data.
Verify Settlement
The 200 response includes a PAYMENT-RESPONSE header with on-chain settlement proof.
If the query fails (timeout, server error, bad parameters), no payment is settled. You only pay for successful responses.
Setup Code
One-time setup that your agent reuses across all requests:
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { registerExactSvmScheme } from "@x402/svm/exact/client";
import { toClientSvmSigner } from "@x402/svm";
import { getBase58Encoder, createKeyPairSignerFromBytes } from "@solana/kit";
import type { PaymentRequired, SettleResponse } from "@x402/core/types";
// Load your Solana keypair
const bytes = getBase58Encoder().encode(process.env.SOLANA_PRIVATE_KEY!);
const signer = await createKeyPairSignerFromBytes(bytes);
// Initialize x402 client
const client = new x402Client();
registerExactSvmScheme(client, { signer: toClientSvmSigner(signer) });
const httpClient = new x402HTTPClient(client);
The paidFetch Function
Wrap the two-step handshake in a reusable function:
const BASE_URL = "https://agent.metengine.xyz";
async function paidFetch(
path: string,
options?: { method?: string; body?: Record<string, unknown> },
): Promise<{ data: unknown; settlement: SettleResponse; price: number }> {
const method = options?.method ?? "GET";
const url = `${BASE_URL}${path}`;
const fetchOpts: RequestInit = { method };
if (options?.body) {
fetchOpts.headers = { "Content-Type": "application/json" };
fetchOpts.body = JSON.stringify(options.body);
}
// Step 1: Get 402 with price
const initial = await fetch(url, fetchOpts);
if (initial.status !== 402)
throw new Error(`Expected 402, got ${initial.status}`);
const body = await initial.json();
// Step 2: Parse payment requirements
const paymentRequired: PaymentRequired =
httpClient.getPaymentRequiredResponse(
(name) => initial.headers.get(name),
body,
);
const price = Number(paymentRequired.accepts[0]!.amount);
// Step 3: Sign payment locally
const paymentPayload =
await httpClient.createPaymentPayload(paymentRequired);
const paymentHeaders =
httpClient.encodePaymentSignatureHeader(paymentPayload);
// Step 4: Re-send with payment
const paid = await fetch(url, {
...fetchOpts,
headers: {
...(fetchOpts.headers as Record<string, string>),
...paymentHeaders,
},
});
if (paid.status !== 200) {
const err = await paid.json();
throw new Error(
`Payment failed (${paid.status}): ${JSON.stringify(err)}`,
);
}
const paidBody = (await paid.json()) as { data: unknown };
// Step 5: Extract settlement proof
const settlement = httpClient.getPaymentSettleResponse(
(name) => paid.headers.get(name),
);
return { data: paidBody.data, settlement, price };
}
Your First Query
Fetch trending Polymarket markets:
const { data, price } = await paidFetch(
"/api/v1/markets/trending?timeframe=24h&limit=5"
);
console.log(`Paid $${price} USDC for ${(data as any[]).length} markets`);
POST endpoint (smart money intelligence for a specific market):
const { data } = await paidFetch("/api/v1/markets/intelligence", {
method: "POST",
body: { condition_id: "0xabc123...", top_n_wallets: 10 },
});
Session Memory for Agents
If your agent runs across multiple sessions, persist setup details to avoid re-reading the full spec every time. Store in ~/.claude/agents/metengine-memory.md:
- Wallet address and balance verification status
- Working bootstrap code snippet
- Last 10 endpoint calls with latency and cost
- Any quirks or fallback strategies discovered
This cuts token overhead by roughly 80% on subsequent sessions.
Error Handling
| Status | Meaning | Action |
|---|
| 402 | Payment required | Normal first step. Parse and sign. |
| 200 | Success | Data returned. Payment settled. |
| 504 | Timeout | No charge. Retry with narrower parameters or use a fallback endpoint. |
| 503/429 | Rate limit | No charge. Back off per Retry-After header. |
| 500 | Server error | No charge. Some endpoints have known fallbacks (see Endpoints). |
Next Steps