X402 Tutorial

Example Code: The complete working example for this tutorial is available at sb-on-demand-examples/solana/x402arrow-up-right

The Problem: Accessing Paywalled Data in Oracles

Many valuable data sources—premium RPC endpoints, institutional APIs, proprietary market data—require payment or authentication. Traditional oracles can't access these sources because:

  1. No way to pay: Oracles can't hold funds or make payments on your behalf

  2. Static credentials: Storing API keys in feed definitions (on IPFS or on-chain) exposes them publicly

  3. Per-request pricing: Many premium services charge per-request, incompatible with polling oracles

X402 solves this by enabling micropayments directly in HTTP requests. The oracle authenticates with the paywalled API using payment headers you provide at runtime, without ever exposing credentials or requiring the oracle to hold funds.

What We're Building

In this tutorial, we'll fetch data from a paywalled Helius RPC endpoint using X402 micropayments. The flow works like this:

┌─────────────────────────────────────────────────────────────────────────────┐
│                              X402 Oracle Flow                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   YOUR APP                           ORACLE (TEE)           PAYWALLED API   │
│   ────────                           ────────────           ─────────────   │
│                                                                             │
│   1. Derive X402 payment ─────┐                                             │
│      headers (USDC auth)      │                                             │
│                               ▼                                             │
│   2. Define feed with    ┌─────────┐                                        │
│      ${PLACEHOLDER}  ───►│Crossbar │                                        │
│      variables           └────┬────┘                                        │
│                               │                                             │
│   3. Pass headers as          │    4. Oracle makes               ┌────────┐ │
│      variable overrides ──────┼─────► authenticated ────────────►│ Helius │ │
│                               │       HTTP request               │  RPC   │ │
│                               │       with X-PAYMENT             └───┬────┘ │
│                               │       header                         │      │
│                               │                                      │      │
│                               │    5. Paywalled data ◄───────────────┘      │
│                               │       returned                              │
│                               ▼                                             │
│   6. Signed oracle data  ┌─────────┐                                        │
│      in quote account ◄──│ Oracle  │                                        │
│                          │Response │                                        │
│                          └─────────┘                                        │
└─────────────────────────────────────────────────────────────────────────────┘

Specifically, we'll:

  • Call getBlockHeight on a paywalled Helius RPC endpoint

  • Pay for the request using USDC micropayments via the X402 protocol

  • Receive the block height as verified oracle data on-chain

This pattern works for any paywalled HTTP API—you're not limited to RPC endpoints.

Prerequisites

  • Solana CLIarrow-up-right installed and configured

  • Node.js 18+

  • A Solana keypair with USDC on mainnet-beta (the X402 payment token)

Installation

Clone the examples repository and install dependencies:

Dependencies

The example uses these X402-specific packages:

How X402 Authentication Works

Unlike standard oracle feeds (stored on IPFS with a feed hash), X402 feeds are defined inline in your code with placeholder variables. At runtime, you:

  1. Derive payment headers from the X402 protocol (these authorize your USDC payment)

  2. Replace placeholders with actual headers via variableOverrides

  3. Oracle executes the authenticated request inside a TEE (Trusted Execution Environment)

The oracle never sees your wallet or credentials—it just receives the pre-signed authentication headers.

Implementation

Step 1: Set Up Imports and Constants

Step 2: Define the Oracle Feed with Placeholders

This is the key difference from standard feeds. Instead of storing the feed on IPFS, we define it inline with placeholder variables for the authentication headers:

Key points:

  • ${X402_PAYMENT_HEADER} and ${X402_SWITCHBOARD_PAYMENT_HEADER} are placeholders that get replaced at runtime

  • The oracle sees the actual header values, but they're never stored permanently anywhere

  • minJobResponses: 1 and minOracleSamples: 1 because X402 payments are single-use (you can't have multiple oracles reuse the same payment header)

Step 3: Initialize Payment Infrastructure

Faremeter is the payment infrastructure powering X402. We create a wallet and payment handler that will authorize USDC payments:

Step 4: Check USDC Balance

X402 payments are made in USDC. Verify you have sufficient balance before proceeding:

Step 5: Derive X402 Payment Headers

This is where the magic happens. The X402FetchManager derives cryptographic payment headers that:

  • Prove you've authorized a USDC payment for this specific request

  • Are bound to the exact URL, method, and body (can't be reused for different requests)

  • Are single-use (can't be replayed)

Important: These headers are single-use. Once the oracle uses them, they can't be used again.

Step 6: Fetch Managed Update with Variable Overrides

Now we bring it all together. We pass our payment headers as variable overrides, which replace the ${PLACEHOLDER} values in our feed definition:

The returned instructions contain:

  1. Ed25519 signature verification - Proves the oracle signed the response

  2. Quote program update - Writes verified data to the quote account

Step 7: Build and Send Transaction

Finally, bundle the oracle instructions with your program's instruction and submit:

After the transaction confirms, the quoteAccount contains the verified block height from the paywalled RPC.

Important Constraints

Why numSignatures Must Be 1

X402 payment headers are single-use. Each header can only authenticate one oracle request. If you set numSignatures: 2, the second oracle would try to reuse the same payment header and fail.

Simulation Warning: Don't Pay Twice

The X402 payment is charged when the oracle makes the HTTP request, not when your transaction lands on-chain. This means:

  • Crossbar simulation (crossbar.simulateFeed()) will charge you

  • On-chain simulation (connection.simulateTransaction()) is safe (no HTTP call)

Why Inline Feeds?

Standard Switchboard feeds are stored on IPFS and referenced by hash. X402 feeds must be defined inline because:

  1. Payment headers change with every request

  2. Headers contain sensitive payment authorization

  3. The feed definition contains runtime placeholders, not static values

Running the Example

Expected output:

Next Steps

Last updated