Self-Hosted Facilitator
Run your own facilitator for complete control over your payment infrastructure.
Prerequisites
- Node.js 18+
- A wallet with MNT for gas fees (~0.001 MNT per transaction)
- Access to Mantle RPC
Create Facilitator
npx create-mantle-facilitator
cd your-facilitator-path
npm install
The CLI will guide you through the setup and automatically generate a FACILITATOR_SECRET for secure authentication.
Configuration
Edit .env:
# Required
FACILITATOR_PRIVATE_KEY=0x... # Wallet that pays gas
RPC_URL=https://rpc.mantle.xyz
FACILITATOR_SECRET=fac_xxx... # Auto-generated, share with your backend
# Optional
PORT=8080
USDC_ADDRESS=0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9
NETWORK_ID=mantle-mainnet
CHAIN_ID=5000
# Telemetry (Optional)
# TELEMETRY_PROJECT_KEY=pk_xxx # Get from dashboard
Configuration Validation
Required variables are validated at startup with helpful error messages:
- FACILITATOR_PRIVATE_KEY — Must be 66 chars (0x + 64 hex)
- FACILITATOR_SECRET — Required for secure authentication
- RPC_URL — Must be valid URL
- USDC_ADDRESS — Must be valid Ethereum address
If validation fails, you'll see step-by-step fix instructions in the console.
Startup Banner
When the facilitator starts successfully, you'll see:
+--------------------------------------------------+
| Mantle x402 Facilitator |
+--------------------------------------------------+
| Network: mantle-mainnet (5000) |
| Address: 0xAbcd...ef01 |
| Port: 8080 |
| Telemetry: disabled |
+--------------------------------------------------+
Run Locally
# Development
npm run dev
# Production
npm run build
npm start
Connecting to Your Backend
Copy FACILITATOR_SECRET from your facilitator's .env to your backend environment, then configure the SDK:
import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/express';
// Self-hosted facilitator (requires facilitatorUrl + facilitatorSecret)
const pay = mantlePaywall({
priceUsd: 0.01,
payTo: '0xYourWallet',
facilitatorUrl: 'https://your-facilitator.com', // Required
facilitatorSecret: process.env.FACILITATOR_SECRET!, // Required
// projectKey: 'pk_xxx' // Optional: for analytics
});
When using facilitatorSecret, facilitatorUrl is required. The URL is automatically passed to clients via 402 responses, so frontend code doesn't need to configure it.
Security
Why is FACILITATOR_SECRET required?
Without the secret, anyone who knows your facilitator's URL could use it to process their own payments — and you would pay the gas fees from your wallet.
The FACILITATOR_SECRET ensures that only your backend can authorize transactions on your facilitator:
- Your backend includes a cryptographic
settleToken(derived from the secret) in 402 responses - When the client sends a payment to settle, it includes this token
- Your facilitator verifies the token before executing the transaction
Without this protection: Bad actors could send arbitrary payment headers to your /settle endpoint and drain your MNT balance.
Telemetry
When TELEMETRY_PROJECT_KEY is set, the facilitator sends anonymous analytics:
What is sent:
- Payment metadata (buyer address, amount, asset, network)
- Transaction hash
- Timestamp
What is NOT sent:
- Private keys
- Personal information
- Request/response payloads
Get your project key from Dashboard.
Telemetry errors never affect payment processing — if analytics backend is down, payments continue normally.
Next Steps
- Facilitator Overview — How facilitators work
- Hosted Facilitator — Managed service option
- Dashboard — Analytics and monitoring