Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Accept x402 escrow payments in 15 minutes · Boson Protocol
Skip to content

Accept x402 escrow payments in 15 minutes

What you'll build: an Express server that protects a resource behind an x402 Boson escrow payment challenge. Buyers sign a meta-transaction; a facilitator relays it to the Diamond; on success, the server returns the protected resource.

Time: 15 minutes. Stack: Node.js 20+, Express, @bosonprotocol/x402-server-express. Network: Base Sepolia.

1. Project

mkdir x402-seller && cd x402-seller
pnpm init
pnpm add express @bosonprotocol/x402-server-express @bosonprotocol/x402-core ethers@^5
pnpm add -D tsx typescript @types/node @types/express

2. Server

// server.ts
import express from "express"
import { createX402bServerExpress } from "@bosonprotocol/x402-server-express"
import { ethers } from "ethers"
 
const wallet = new ethers.Wallet(process.env.SELLER_PRIVATE_KEY!)
 
const app = express()
 
const x402 = createX402bServerExpress({
  network: "base-sepolia",
  chainId: 84532,
  escrow: {
    configId: "staging-84532-0",
    sellerId: "2",
    productUuid: "ec00f1a5-2c96-4d22-9d80-2a7c12345678",
  },
  signer: wallet,
  facilitator: {
    url: "https://facilitator.example.com", // your or a hosted facilitator
  },
})
 
app.get("/api/premium-data", x402.middleware(), async (req, res) => {
  // If we got here, payment is settled. The exchangeId is on req.x402.
  res.json({
    exchangeId: req.x402!.exchangeId,
    data: "Here is the thing you paid for.",
  })
})
 
app.listen(3000, () => console.log("x402 server listening on :3000"))

Run it:

SELLER_PRIVATE_KEY=0x... pnpm tsx server.ts

3. Make a paid request

From a buyer client:

import { createX402bClientFetch } from "@bosonprotocol/x402-client-fetch"
import { ethers } from "ethers"
 
const wallet = new ethers.Wallet(process.env.BUYER_PRIVATE_KEY!)
const fetchWithPayment = createX402bClientFetch({ signer: wallet })
 
const res = await fetchWithPayment("http://localhost:3000/api/premium-data")
console.log(await res.json())

The client:

  1. Issues a plain GET.
  2. Receives 402 Payment Required with a Boson escrow option.
  3. Signs a meta-transaction + token authorization.
  4. Re-issues the GET with an X-PAYMENT header.
  5. The server's middleware validates, the facilitator settles on-chain, the response is delivered.

Common gotchas

  • Facilitator must be reachable from the server's network. If the facilitator is in a private VPC, configure ingress.
  • Token-auth strategy mismatch. Buyer and server must agree on at least one of: ERC-3009, EIP-2612, Permit2, plain approve. See x402 → Token-auth strategies.
  • State machine drift. If you advance the exchange (e.g. atomic redeem) inside the middleware, declare it in nextActions. See x402 → State-machine integration.

Next