[](https://www.npmjs.com/package/create-mantle-facilitator) [](https://opensource.org/licenses/MIT)
npm install create-mantle-facilitatorbash
npx create-mantle-facilitator
cd my-facilitator # or the name you chose
npm install
npm run dev
`
The CLI will guide you through the setup:
`
Welcome to Mantle Facilitator Setup!
? Where should we create the facilitator? my-facilitator
? RPC URL for Mantle network: https://rpc.mantle.xyz
? Facilitator wallet private key: (optional, set later)
? USDC contract address: 0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9
? Enable telemetry? (Send anonymous usage stats) No
✓ Done! Your facilitator is ready.
`
Configuration
After creation, edit the .env file:
`env
Required
FACILITATOR_PRIVATE_KEY=0x... # Wallet that pays gas fees
RPC_URL=https://rpc.mantle.xyz # Mantle RPC endpoint
FACILITATOR_SECRET=fac_xxx... # Auto-generated security secret
Optional
USDC_ADDRESS=0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9
PORT=8080
NETWORK_ID=mantle-mainnet
CHAIN_ID=5000
Telemetry (Optional - always present in .env)
TELEMETRY_PROJECT_KEY=your_project_key_here
Get your key from https://x402mantlesdk.xyz/dashboard
`
Note: The telemetry section is always added to .env (commented out if disabled during setup). To enable later, just uncomment and add your project key.
$3
- FACILITATOR_PRIVATE_KEY: This wallet will pay gas fees for all settlements. Make sure it has MNT for gas.
- FACILITATOR_SECRET: Auto-generated during setup. Copy this to your backend's environment variables to enable secure authentication.
- Security: Never commit .env to version control. The generated .gitignore already excludes it.
$3
Add FACILITATOR_SECRET to your backend and configure the SDK:
`typescript
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 for self-hosted
facilitatorSecret: process.env.FACILITATOR_SECRET!, // Required for self-hosted
// projectKey: process.env.PROJECT_KEY, // Optional: for analytics
});
`
Note: When using facilitatorSecret (self-hosted mode), facilitatorUrl is required. The URL is automatically passed to clients via 402 responses, so frontend code doesn't need to configure it.
Running Locally
`bash
Development mode (hot reload)
npm run dev
Build for production
npm run build
Run production build
npm start
`
Facilitator runs on http://localhost:8080 by default.
$3
When the facilitator starts successfully, you'll see a banner:
`
+--------------------------------------------------+
| Mantle x402 Facilitator |
+--------------------------------------------------+
| Network: mantle-mainnet (5000) |
| Address: 0xAbcd...ef01 |
| Port: 8080 |
| Telemetry: disabled |
+--------------------------------------------------+
Note: Telemetry is disabled.
To enable analytics, set TELEMETRY_PROJECT_KEY in .env
Get your key at https://x402mantlesdk.xyz/dashboard
Server listening on http://localhost:8080
`
$3
The facilitator validates all required environment variables at startup with helpful error messages:
- FACILITATOR_PRIVATE_KEY: Must be 66 chars (0x + 64 hex digits)
- FACILITATOR_SECRET: Required for secure authentication
- RPC_URL: Must be valid URL (http:// or https://)
- USDC_ADDRESS: Must be valid Ethereum address
If validation fails, you'll see step-by-step fix instructions in the console.
---
Deployment
Deploy your facilitator to any Node.js hosting platform.
$3
`dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 8080
CMD ["npm", "start"]
`
`bash
docker build -t my-facilitator .
docker run -p 8080:8080 --env-file .env my-facilitator
`
$3
`bash
npm install -g @railway/cli
railway login
railway init
railway up
`
Then add environment variables in Railway dashboard.
---
API Endpoints
$3
Returns facilitator status and wallet info.
`bash
curl http://localhost:8080/health
`
`json
{
"status": "ok",
"network": "mantle-mainnet",
"chainId": 5000,
"facilitatorAddress": "0x...",
"blockNumber": 12345678,
"mntBalance": "1.5"
}
`
$3
Returns supported networks and assets.
`bash
curl http://localhost:8080/supported
`
`json
{
"x402Version": 1,
"schemes": ["exact"],
"networks": ["mantle-mainnet"],
"assets": {
"mantle-mainnet": [{
"address": "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9",
"symbol": "USDC",
"decimals": 6
}]
}
}
`
$3
Verifies a payment header without executing.
`bash
curl -X POST http://localhost:8080/verify \
-H "Content-Type: application/json" \
-d '{
"x402Version": 1,
"paymentHeader": "base64...",
"paymentRequirements": {...}
}'
`
`json
{
"isValid": true
}
`
$3
Executes the USDC transfer on-chain. Requires a valid settleToken for authentication.
`bash
curl -X POST http://localhost:8080/settle \
-H "Content-Type: application/json" \
-d '{
"x402Version": 1,
"paymentHeader": "base64...",
"paymentRequirements": {...},
"settleToken": "base64..."
}'
`
`json
{
"success": true,
"txHash": "0x..."
}
`
Note: The settleToken is automatically generated by the SDK when facilitatorSecret is configured, and passed through the client to authenticate with your facilitator.
---
How It Works
`
┌─────────────────────────────────────────────────────────────────┐
│ Settlement Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Client signs EIP-712 authorization (gasless for user) │
│ │ │
│ ▼ │
│ 2. Client sends to facilitator POST /settle │
│ │ │
│ ▼ │
│ 3. Facilitator verifies signature │
│ │ │
│ ▼ │
│ 4. Facilitator calls USDC.transferWithAuthorization() │
│ - Pays gas in MNT │
│ - USDC transfers from user → merchant │
│ │ │
│ ▼ │
│ 5. Returns txHash to client │
│ │
└─────────────────────────────────────────────────────────────────┘
`
The facilitator uses EIP-3009 transferWithAuthorization which allows:
- Gasless for users: Users only sign, never pay gas
- Atomic transfers: Signature + transfer in one transaction
- Replay protection: Nonces prevent double-spending
---
Supported Tokens
Currently, the facilitator supports USDC only for gasless payments.
$3
Gasless payments require tokens that implement the EIP-3009 standard (transferWithAuthorization). This standard allows users to sign a payment authorization off-chain, while the facilitator submits the transaction and pays gas fees.
On Mantle mainnet, USDC is currently the only token that implements EIP-3009. As other stablecoins and tokens adopt this standard, we will add support for them.
| Token | EIP-3009 Support | Status |
|-------|------------------|--------|
| USDC | Yes | Supported |
| USDT | No | Not available |
| DAI | No | Not available |
| Other tokens | — | Pending EIP-3009 adoption |
---
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
- Facilitator address
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.
---
Security Considerations
1. Facilitator Secret (REQUIRED)
- FACILITATOR_SECRET prevents unauthorized usage of your facilitator
- Without it, anyone could use your facilitator URL to settle their payments and drain your gas wallet
- The secret creates a secure token flow: Backend → Client → Facilitator
- Always set facilitatorSecret in your backend SDK configuration
2. Private Key Security
- Never commit .env` to git