This project provides a complete implementation of the x402 Protocol for Express.js applications, utilizing the Algorand blockchain for payments. It includes a drop-in Express middleware for protecting routes, a payment facilitator for verifying and settling transactions, and a pre-built paywall UI.
This implementation is based on the exact
payment scheme on Algorand, as detailed in the scheme_exact_algo.md
specification written by @nullun and team.
- Drop-in Middleware: Easily add payment requirements to any Express route.
- Built-in Facilitator: Handles the complexities of Algorand transaction verification and settlement.
- Gasless Transactions: Supports a "fee payer" model where the facilitator covers network fees for a smoother user experience.
- Inbuilt Paywall: A pre-built React-based paywall that is automatically presented to users in a web browser.
- Algorand Native: Uses Algorand Standard Assets (ASAs) and Atomic Transfers for secure and efficient payments with instant finality.
The x402 protocol defines a standard for HTTP 402 Payment Required
errors, enabling machine-readable payment information. This project implements that standard using Algorand's unique features.
The flow is as follows:
- Request: A client requests a protected resource from the Express server.
- 402 Response: The server, via the
paymentMiddleware
, responds with a402 Payment Required
status. The response includespaymentRequirements
detailing the required asset, amount, and network. For browsers, it serves a full HTML paywall. - Payment Construction: The client's wallet (the provided paywall UI) constructs an Algorand atomic transaction group to satisfy the requirements.
- Resend with Payment: The client resends the original request, this time including the signed transaction group in an
X-PAYMENT
header. - Verification: The middleware intercepts the request and uses the built-in Facilitator to verify the payment. The facilitator:
- Decodes the transaction group.
- Checks that the payment amount, asset, and receiver are correct.
- If a
feePayer
is configured, checks that harmful params such as closeRemainderTo, rekeyTo, amount > 0, etc. are not present in the fee transaction and then signs the fee transaction. - Simulates the entire transaction group against an Algorand node to ensure it will succeed.
- Settlement & Resource Access: If verification succeeds, the middleware proceeds to the protected route handler. After the handler generates a successful response, the facilitator settles the payment by submitting the transaction group to the Algorand network. Thanks to Algorand's instant finality, the payment is confirmed immediately, and the server returns the resource to the client with a
200 OK
.
x402-express-algo/
├── public/
│ └── paywall.html # The final single-file paywall UI
├── paywall/ # Source code for the React paywall application
│ ├── src/
│ ├── package.json
│ └── webpack.config.js
├── src/
│ ├── index.ts # Express server entry point and middleware usage example
│ ├── facilitator/ # Logic for payment verification and settlement
│ └── middleware/ # The core x402 Express middleware
├── scripts/
│ └── copy-paywall.js # Helper script to copy the paywall build output
└── package.json
- Node.js (v22 or higher)
- pnpm package manager
Clone the repository and install the dependencies for both the root project and the paywall
workspace.
git clone https://github.com/satishccy/x402-express-algo.git
cd x402-express-algo
pnpm install
pnpm --filter paywall install
The server relies on environment variables for facilitator configuration. Create a .env
file in the project root:
# .env
# The mnemonic of the Algorand account that will act as the facilitator
# This account pays network fees if the feePayer model is enabled.
# Make sure this account is funded on the respective network (TestNet/MainNet).
FACILITATOR_MNEMONIC="your 25-word mnemonic phrase here"
# Optional: The port for the Express server to run on
PORT=3000
To start the Express server with hot-reloading for development:
pnpm dev
This will start the server, and you can access it at http://localhost:3000
. Any changes in the src/
directory will automatically restart the server.
The React paywall is built into a single, self-contained HTML file. This allows it to be easily served by the middleware without complex static file handling.
To build the paywall and copy it to the public/
directory, run:
pnpm run build:paywall
This command performs two actions:
- Runs the
build
script in thepaywall/
workspace using Webpack. - Executes
scripts/copy-paywall.js
to move the output topublic/paywall.html
.
To build the TypeScript server for production:
pnpm build
This compiles the code from src/
into dist/
.
To run the compiled server:
pnpm start
The middleware is initialized with the payment receiver's address, a route configuration object, and the facilitator configuration.
Here is the example from src/index.ts
:
import express from "express";
import { paymentMiddleware } from "./middleware";
import "dotenv/config";
import algosdk from "algosdk";
// Load facilitator account from environment variables
const facilitator_mnemonic = process.env.FACILITATOR_MNEMONIC!;
const account = algosdk.mnemonicToSecretKey(facilitator_mnemonic);
const app = express();
app.use(
paymentMiddleware(
// 1. The address that will receive payments
"SATISHQOPKE5WFYSLDMUTDBTWMH25LEJFOHVUEVOU3WXS2ZCFJGYIAVXME",
// 2. Route configuration
{
"/protected": {
price: "$0.01", // Requires $0.01 of the default stablecoin (USDC)
network: "algorand-testnet",
},
"/protected2": {
price: { asset: { id: 700965019, decimals: 6 }, amount: 0.25 }, // Requires 0.25 of a specific asset
network: "algorand",
},
},
// 3. Facilitator configuration
{
account: account,
feePayer: true, // Enable gasless transactions
}
)
);
// This route is now protected by the middleware
app.get("/protected", (_req, res) => {
res.status(200).send("<h1>Access Granted!</h1>");
});
app.listen(3000, () => {
console.log(`Server listening on http://localhost:3000`);
});
This project is licensed under the MIT License.