solana-pay-qr-code-x402-express
Version:
An Express middleware that combines x402 payment requests with a Solana Pay QR code paywall.
113 lines (85 loc) • 4.29 kB
Markdown
# Solana Pay x402 Middleware
[](https://www.npmjs.com/package/solana-pay-x402-middleware)
[](https://opensource.org/licenses/MIT)
A drop-in replacement for the `x402-express` `paymentMiddleware` that automatically generates a beautiful, user-friendly Solana Pay QR code paywall.
This middleware intercepts 402 Payment Required responses for Solana-configured routes and replaces the default response with a custom HTML page displaying a Solana Pay QR code. It's designed to be a seamless upgrade for developers already using the x402 protocol.
## Features
- **Drop-in Replacement:** Call it exactly like you would call `paymentMiddleware` from `x402-express`.
- **QR Code Paywall:** Automatically generates and displays a Solana Pay QR code for a superior user experience.
- **Mobile Friendly:** Includes a direct payment link (`solana:`) for a one-click experience on mobile wallets.
- **No `async/await` Needed:** Integrates synchronously during server setup for clean, simple, and familiar code.
- **TypeScript Ready:** Fully typed for a great developer experience.
## Installation
```bash
npm install solana-pay-x402-middleware /web3.js express
```
## How to Use
Simply import `solanaPayQRMiddleware` and use it in place of `paymentMiddleware`. The function signature is identical, making migration trivial.
Here is a complete example of an Express server:
```typescript
// server/index.ts
import express from "express";
import { facilitator } from "@coinbase/x402"; // Or your preferred facilitator
import { solanaPayQRMiddleware } from "solana-pay-x402-middleware";
// --- 1. Server Setup ---
const app = express();
const PORT = process.env.PORT || 3000;
const MERCHANT_WALLET =
process.env.MERCHANT_SOLANA_ADDRESS || "REPLACE_WITH_YOUR_SOLANA_ADDRESS";
if (MERCHANT_WALLET === "REPLACE_WITH_YOUR_SOLANA_ADDRESS") {
console.warn(
"⚠️ WARNING: Please replace the placeholder Solana address in your environment or code."
);
}
// --- 2. x402 Configuration ---
// Define which routes require payment.
const routeConfigs = {
// Protect this route with a 0.01 SOL payment
"GET /api/premium-content": {
// NOTE: For the solana network, this price is treated as SOL.
price: "$0.01",
network: "solana" as const,
},
// This ethereum route will function normally without a QR code
"GET /api/other-content": {
price: "$0.05",
network: "ethereum" as const,
},
// This route remains free
"GET /api/free-content": {
price: "$0.00",
},
};
// --- 3. Apply Middleware ---
// The call is synchronous and identical to the original paymentMiddleware.
// It replaces the standard 402 error with the Solana Pay UI for Solana routes.
app.use(solanaPayQRMiddleware(MERCHANT_WALLET, routeConfigs, facilitator));
// --- 4. Define Your API Routes ---
app.get("/api/premium-content", (req, res) => {
res.send({
message: "This is top-secret premium content, unlocked with Solana!",
timestamp: new Date().toISOString(),
});
});
app.get("/api/free-content", (req, res) => {
res.send({ message: "This content is free for everyone to access." });
});
app.get("/api/other-content", (req, res) => {
res.send({ message: "This content was paid for on another chain." });
});
// --- 5. Start Server ---
app.listen(PORT, () => {
console.log(`🚀 Server running at http://localhost:${PORT}`);
console.log(
`💎 Protected Solana route: http://localhost:${PORT}/api/premium-content`
);
});
```
### Paywall Preview
When a user accesses a protected Solana route without a valid payment, they will see this page instead of a plain error:
---
### **Important Note on Price**
For any route configured with `"network": "solana"`, this middleware assumes the `price` field is denominated in **SOL**, not USD. It will strip the `$` sign for compatibility, but the numeric value is treated as SOL.
In a full production application, you should integrate a price oracle (like Pyth or Chainlink) to dynamically convert a USD price to the correct amount of SOL before passing the configuration to the middleware.
## License
This project is licensed under the [MIT License](LICENSE).