All articles
solanax402paymentsfacilitatordeveloper-tools

Build an x402 seller on Solana (and when to run your own facilitator)

A hands-on guide to accepting x402 payments on Solana: the v2 middleware, the Solana 'exact' scheme (partially-signed tx, TransferChecked, memo nonce, blockhash expiry), replay protection, and the verify/settle/supported endpoints if you self-host the facilitator.

Share

The x402 protocol piece shows the wire flow and the PayAI piece shows how to delegate settlement in one line. This is the builder's middle ground: what you actually need to know to ship a production x402 seller on Solana — the v2 middleware, the Solana exact scheme down to the instruction order, replay protection, and the decision of whether to run your own facilitator.

First: you're probably on v2, and it renamed everything

x402 shipped a v1→v2 rewrite in early 2026 (it now sits under a Linux Foundation initiative). If you're following an older tutorial, three things changed and will bite you:

  • Packages — unscoped x402-express / x402-hono are deprecated; use scoped @x402/express, @x402/hono, @x402/next, with @x402/svm for Solana.
  • Headers — the old X-PAYMENT / X-PAYMENT-RESPONSE became PAYMENT-REQUIRED (the 402 challenge), PAYMENT-SIGNATURE (client→server), and PAYMENT-RESPONSE (settlement outcome).
  • Network IDs — CAIP-2 identifiers now. Solana mainnet is solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp... (the genesis hash), not a friendly string.

The seller: middleware over your routes

A seller (the resource server) doesn't talk to the chain. It declares a price per route and points at a facilitator; the middleware does the 402 challenge and, on retry, calls the facilitator's /verify and /settle. The v2 shape uses an accepts array per route — each entry is one payment option the client may choose:

typescript
import express from "express"
import { paymentMiddleware } from "@x402/express"

const app = express()

app.use(
  paymentMiddleware(
    {
      "GET /premium": {
        accepts: [
          {
            scheme:  "exact",
            price:   "$0.001",                 // facilitator resolves to USDC atomic units
            network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // mainnet (genesis hash, truncated)
            payTo:   "<merchant-solana-address>",
          },
        ],
        description: "Premium data endpoint",
        mimeType:    "application/json",
      },
    },
    server,                                    // facilitator config
  ),
)

app.get("/premium", (_req, res) => res.json({ data: "the paid content" }))
app.listen(3000)

That's the whole seller. The same shape exists for Hono and Next, and there's an official Python path — pip install "x402[fastapi]" with x402[svm] for Solana — if your backend is FastAPI or Flask.

The 402 challenge fields

When an unpaid request hits a gated route, the middleware answers 402 with a PaymentRequirements object. The fields that matter:

  • scheme"exact": pay exactly this amount of this asset.
  • network — CAIP-2 chain id.
  • maxAmountRequired — the price in atomic units.
  • asset — the SPL mint (USDC on Solana).
  • payTo — merchant address.
  • resource — what's being bought.
  • maxTimeoutSeconds — how long the client has to pay (default 60).

The Solana "exact" scheme, concretely

This is where Solana differs from the EVM path, and it's worth understanding even if a facilitator handles it. The client builds a partially-signed Solana transaction with instructions in a strict order:

text
1. ComputeBudget: set compute-unit limit
2. ComputeBudget: set CU price        (capped — must stay <= 5 lamports/CU)
3. SPL Token TransferChecked          (the actual payment to merchant's ATA)
4-6. optional: Memo (nonce) and/or Lighthouse assertions

Client signs everything EXCEPT the fee payer.
The facilitator adds the fee-payer signature, so it sponsors the gas.
Tx is base64-encoded into the payment payload.

The facilitator then enforces a fixed rule set before it settles: instruction layout is exactly as above; the fee payer is "safe" (not the source, authority, or otherwise in the token accounts); the compute-budget price is within cap; the transfer destination is the merchant's derived associated token account and that ATA exists; and the amount exactly equals what was required. Any deviation and it refuses.

Replay protection (it's not what you'd guess)

On EVM, replay protection rides on a signed authorization with a deadline. On Solana, it's two native mechanisms:

  • Recent blockhash. A Solana tx embeds a blockhash with a ~60–90s validity window. After that the network itself rejects it — free expiry, no nonce table needed.
  • A Memo nonce. The exact-SVM scheme requires a Memo instruction carrying a seller-provided value or a random nonce (≥16 bytes, hex). The facilitator keeps a short-lived in-memory cache of seen payloads (evicting after ~120s) so the same signed tx can't be settled twice inside its window.

Note what's not in the spec: refunds and prepaid-credit batching are not protocol primitives. They're application-level patterns. If you want "pay $1 for 1,000 calls," you build that yourself on top.

Running your own facilitator

Most sellers should just use a hosted facilitator — PayAI on Solana (gasless for both sides; free up to 10k settlements/month) or Coinbase's. You'd self-host when you need custom validation, a non-default SPL token, your own gas-sponsorship policy, or compliance control. A facilitator is just three endpoints:

  • POST /verify — "is this payload valid for this requirement?" Returns { isValid, payer, invalidReason? } without broadcasting.
  • POST /settle — broadcast and confirm; returns { success, payer, transaction, network }.
  • GET /supported — the (scheme, network) tuples it handles.

You don't have to start from zero. Solana's own guide builds a facilitator on top of Kora (a Solana signer node for gasless/fee-abstracted transactions): /verify maps to Kora's validate-and-sign, /settle to sign-and-send. There's also x402-rs (a Rust facilitator binary supporting v1 and v2) and thirdweb's Solana support, which gives you the three endpoints backed by your own server wallet rather than running the facilitator for you.

The honest read

Building the seller is genuinely a few lines — the protocol did its job. The real work is operational, and there are three things worth respecting. Latency: every gated call adds a /verify round-trip and, on success, an on-chain /settle; Solana's ~400ms finality (and ~$0.00025 fees, per Solana's figures) make this viable, but it's not free — for hot paths, batch with prepaid credits. Self-hosting is a real commitment: a facilitator is a signing service that fronts gas and must never settle a bad tx, so unless you need the control, don't run one. And verify amounts and mints yourself if you're holding value — the convenience of a hosted facilitator is also a trust point. For low-stakes, high-volume, agent-driven endpoints, the hosted path is the right default; reach for your own facilitator only when policy demands it.

References

Accepting machine payments on Solana went from "build a settlement system" to "add middleware and pick a facilitator." The depth here isn't in the happy path — it's in knowing the exact scheme, the replay model, and exactly when to take settlement into your own hands.