This example is for learning purposes only. Do not use it for production.
Prerequisites
Before setting up a facilitator, ensure you have:
- Node.js 18+ installed
- Sei wallet with some SEI for gas fees
- Private key for your facilitator wallet (testnet recommended for development)
Create Your First Facilitator
Install Dependencies
Create a new project and install the required packages:mkdir my-facilitator && cd my-facilitator
pnpm init -y
pnpm add x402 @coinbase/x402 express dotenv tsx
Expected outcome: Project directory created with facilitator dependencies installed.
Environment Configuration
Create a .env
file in your project root:# Required: Your facilitator private key
PRIVATE_KEY=0xYourPrivateKeyHere
# Optional: Server port (defaults to 3000)
PORT=3000
Security Note: Never commit private keys to version control. Use environment variables or secure key management services in production. For testing, you can use a dummy private key.
Expected outcome: Environment variables configured for your facilitator.
Create the facilitator server
Create index.ts
with the facilitator implementation:import { config } from "dotenv";
import express from "express";
import { verify, settle } from "x402/facilitator";
import {
PaymentRequirementsSchema,
PaymentRequirements,
evm,
PaymentPayload,
PaymentPayloadSchema,
} from "x402/types";
config();
const PRIVATE_KEY = process.env.PRIVATE_KEY;
if (!PRIVATE_KEY) {
console.error("Missing required environment variables");
process.exit(1);
}
const { createConnectedClient, createSigner } = evm;
const app = express();
app.use(express.json());
type VerifyRequest = {
paymentPayload: PaymentPayload;
paymentRequirements: PaymentRequirements;
};
type SettleRequest = {
paymentPayload: PaymentPayload;
paymentRequirements: PaymentRequirements;
};
const client = createConnectedClient("sei-testnet");
// Verification endpoint
app.post("/verify", async (req, res) => {
try {
const body: VerifyRequest = req.body;
const paymentRequirements = PaymentRequirementsSchema.parse(
body.paymentRequirements
);
const paymentPayload = PaymentPayloadSchema.parse(body.paymentPayload);
const valid = await verify(client, paymentPayload, paymentRequirements);
res.json(valid);
} catch {
res.status(400).json({ error: "Invalid request" });
}
});
// Settlement endpoint
app.post("/settle", async (req, res) => {
try {
const signer = createSigner("sei-testnet", PRIVATE_KEY as `0x${string}`);
const body: SettleRequest = req.body;
const paymentRequirements = PaymentRequirementsSchema.parse(
body.paymentRequirements
);
const paymentPayload = PaymentPayloadSchema.parse(body.paymentPayload);
const response = await settle(signer, paymentPayload, paymentRequirements);
res.json(response);
} catch (error) {
res.status(400).json({ error: `Invalid request: ${error}` });
}
});
// Supported schemes endpoint
app.get("/supported", (req, res) => {
res.json({
kinds: [
{
x402Version: 1,
scheme: "exact",
network: "sei-testnet",
},
],
});
});
app.listen(process.env.PORT || 3000, () => {
console.log(
`Server listening at http://localhost:${process.env.PORT || 3000}`
);
});
Expected outcome: Facilitator server code created with verification and settlement endpoints.
Start and test your facilitator
Start your facilitator server:In another terminal, test the supported schemes endpoint:curl http://localhost:3000/supported
Expected outcome: Your facilitator server should start and display: Server listening at http://localhost:3000
The facilitator provides three endpoints: /verify
for payment verification, /settle
for transaction settlement, and /supported
for listing supported payment schemes.
Example response from /supported
:{
"kinds": [
{
"x402Version": 1,
"scheme": "exact",
"network": "sei-testnet"
}
]
}
API Endpoints
Your facilitator exposes three main endpoints:
POST /verify
Verifies x402 payment payloads without executing transactions.
Request Body:
{
paymentPayload: PaymentPayload; // x402 payment data
paymentRequirements: PaymentRequirements; // Payment requirements
}
Response:
{
"valid": true,
"reason": "Payment payload is valid"
}
POST /settle
Settles verified payments by signing and broadcasting transactions to Sei testnet.
Request Body:
{
paymentPayload: PaymentPayload; // x402 payment data
paymentRequirements: PaymentRequirements; // Payment requirements
}
Response:
{
"transactionHash": "0x...",
"status": "success"
}
GET /supported
Returns supported payment schemes and networks.
Response:
{
"kinds": [
{
"x402Version": 1,
"scheme": "exact",
"network": "sei-testnet"
}
]
}