Skip to main content

Express.js Integration

Start accepting x402 payments in your Express server in 2 minutes

Share
Last updated on August 20, 2026

Start accepting x402 payments in your Express server in 2 minutes.

Example Code

You can find the full code for this example on GitHub.

Step 1: Install Dependencies

Install the required packages for your Express server:

bash
npm install x402 express dotenv

Or with other package managers:

bash
# pnpm
pnpm add x402 express dotenv
 
# yarn
yarn add x402 express dotenv
 
# bun
bun add x402 express dotenv

Step 2: Set Your Environment Variables

Open your generated project's .env and set:

  • FACILITATOR_URL: Facilitator base URL (defaults to: https://x402.bex.co)
  • NETWORK: Network to use for the facilitator (default: sui)
  • ADDRESS: Wallet public address to receive payments to
  • BEX_API_KEY: Your bex.co API key from dashboard
env
FACILITATOR_URL=https://x402.bex.co
NETWORK=sui
ADDRESS=0x... # wallet public address you want to receive payments to
BEX_API_KEY=your_api_key_here
Network Options

bex.co supports multiple networks:

  • sui (recommended for fastest settlement)
  • ethereum
  • base
  • polygon
  • avalanche

Step 3: Create Your Express Server

Create an index.ts file with the following code:

typescript
import { config } from "dotenv";
import express from "express";
import { paymentMiddleware, Network, Resource } from "x402-express";
 
config();
 
const facilitatorUrl = process.env.FACILITATOR_URL as Resource;
const payTo = process.env.ADDRESS as `0x${string}`;
const network = process.env.NETWORK as Network;
const apiKey = process.env.BEX_API_KEY;
 
if (!facilitatorUrl || !payTo || !apiKey || !network) {
  console.error("Missing required environment variables");
  process.exit(1);
}
 
const app = express();
 
app.use(
  paymentMiddleware(
    payTo,
    {
      "GET /weather": {
        // USDC amount in dollars
        price: "$0.001",
        network,
      },
      "/premium/*": {
        // Define atomic amounts in any supported token
        price: {
          amount: "100000",
          asset: {
            address: "0xabc",
            decimals: 18,
            name: "USDC",
          },
        },
        network,
      },
    },
    {
      url: facilitatorUrl,
      apiKey: apiKey,
    },
  ),
);
 
app.get("/weather", (req, res) => {
  res.send({
    report: {
      weather: "sunny",
      temperature: 70,
    },
  });
});
 
app.get("/premium/content", (req, res) => {
  res.send({
    content: "This is premium content",
  });
});
 
app.listen(4021, () => {
  console.log(`Server listening at http://localhost:4021`);
});

Step 4: Run the Server

bash
npx tsx index.ts

Or add a script to your package.json:

json
{
  "scripts": {
    "dev": "tsx watch index.ts",
    "start": "node dist/index.js"
  }
}

Then run:

bash
npm run dev
Your server is now accepting 402 payments!

Step 5: Test the Server

You can test payments against your server locally using HTTP clients like curl, Postman, or by building a client application.

Coming Soon

Client implementation guides for fetch API and axios will be available soon.

Payment Configuration Options

The paymentMiddleware accepts flexible payment configurations:

Simple Dollar Amount

typescript
"GET /weather": {
  price: "$0.001",
  network: "sui",
}

Atomic Token Amount

typescript
"/premium/*": {
  price: {
    amount: "100000",
    asset: {
      address: "0x...",
      decimals: 6,
      name: "USDC",
    },
  },
  network: "sui",
}

Route Patterns

You can use wildcards and specific HTTP methods:

typescript
{
  "GET /weather": { /* ... */ },      // Exact GET route
  "/premium/*": { /* ... */ },        // Any method, wildcard path
  "POST /api/analyze": { /* ... */ }, // Exact POST route
}

Advanced Features

Custom Payment Verification

typescript
app.use(
  paymentMiddleware(payTo, paymentConfig, {
    url: facilitatorUrl,
    apiKey: apiKey,
    onPaymentVerified: (req, paymentData) => {
      console.log("Payment verified:", paymentData.txHash);
      // Custom logging or analytics
    },
  }),
);

Error Handling

typescript
app.use((err, req, res, next) => {
  if (err.name === "X402PaymentError") {
    res.status(402).json({
      error: "Payment required",
      details: err.message,
    });
  } else {
    next(err);
  }
});

Production Deployment

Before deploying to production:

  1. Switch to production facilitator endpoint
  2. Use production network (e.g., sui instead of sui-testnet)
  3. Enable HTTPS for your server
  4. Set up proper error logging
  5. Configure CORS if serving cross-origin clients
typescript
// Production configuration
const app = express();
 
// Enable CORS
app.use(
  cors({
    origin: process.env.ALLOWED_ORIGINS?.split(","),
    credentials: true,
  }),
);
 
// Use production network
app.use(
  paymentMiddleware(
    payTo,
    {
      "GET /weather": {
        price: "$0.01",
        network: "sui", // Production Sui network
      },
    },
    {
      url: "https://x402.bex.co",
      apiKey: process.env.BEX_API_KEY,
    },
  ),
);

Troubleshooting

Common Issues

Payment verification fails

  • Verify your BEX_API_KEY is correct
  • Check that the wallet address format matches the network
  • Ensure the facilitator URL is accessible

CORS errors

  • Add CORS middleware before payment middleware
  • Configure allowed origins properly

Network mismatch

  • Ensure client and server use the same network
  • Check that the token address is valid for the network

Next Steps

Need Help?

Join Our Community

Have questions or want to connect with other developers?

Join Discord

One API key for 30+ chains

bex router is a single multi-chain gateway — one key, one bill, metered in compute units instead of an account per network.

Explore bex router