TypeScript Facilitator
Run your own payment facilitator with /verify and /settle endpoints
exampletypescriptfacilitatorintermediate
Files
2 files in this example
x402 Facilitator Example
Express.js facilitator service that verifies and settles payments on-chain for the x402 protocol.
Prerequisites
- Node.js v20+ (install via nvm)
- pnpm v10 (install via pnpm.io/installation)
- EVM private key with Base Sepolia ETH for transaction fees
- SVM private key with Solana Devnet SOL for transaction fees
Setup
- Copy
.env-localto.env:
cp .env-local .env
and fill required environment variables:
EVM_PRIVATE_KEY- Ethereum private keySVM_PRIVATE_KEY- Solana private keyPORT- Server port (optional, defaults to 4022)
- Install and build all packages from the typescript examples root:
cd ../../
pnpm install && pnpm build
cd facilitator
- Run the server:
pnpm dev
API Endpoints
GET /supported
Returns payment schemes and networks this facilitator supports.
{
"kinds": [
{
"x402Version": 2,
"scheme": "exact",
"network": "eip155:84532"
},
{
"x402Version": 2,
"scheme": "exact",
"network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"extra": {
"feePayer": "..."
}
}
],
"extensions": [],
"signers": {
"eip155": ["0x..."],
"solana": ["..."]
}
}
POST /verify
Verifies a payment payload against requirements before settlement.
Request:
{
"paymentPayload": {
"x402Version": 2,
"resource": {
"url": "http://localhost:4021/weather",
"description": "Weather data",
"mimeType": "application/json"
},
"accepted": {
"scheme": "exact",
"network": "eip155:84532",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"amount": "1000",
"payTo": "0x...",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USDC",
"version": "2"
}
},
"payload": {
"signature": "0x...",
"authorization": {}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:84532",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"amount": "1000",
"payTo": "0x...",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USDC",
"version": "2"
}
}
}
Response (success):
{
"isValid": true,
"payer": "0x..."
}
Response (failure):
{
"isValid": false,
"invalidReason": "invalid_signature"
}
POST /settle
Settles a verified payment by broadcasting the transaction on-chain.
Request body is identical to /verify.
Response (success):
{
"success": true,
"transaction": "0x...",
"network": "eip155:84532",
"payer": "0x..."
}
Response (failure):
{
"success": false,
"errorReason": "insufficient_balance",
"transaction": "",
"network": "eip155:84532"
}
Extending the Example
Adding Networks
Register additional schemes for other networks:
import { registerExactEvmScheme } from "@x402/evm/exact/facilitator";
import { registerExactSvmScheme } from "@x402/svm/exact/facilitator";
const facilitator = new x402Facilitator();
registerExactEvmScheme(facilitator, {
signer: evmSigner,
networks: "eip155:84532",
});
registerExactSvmScheme(facilitator, {
signer: svmSigner,
networks: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
});
Lifecycle Hooks
Add custom logic before/after verify and settle operations:
const facilitator = new x402Facilitator()
.onBeforeVerify(async (context) => {
// Log or validate before verification
})
.onAfterVerify(async (context) => {
// Track verified payments
})
.onVerifyFailure(async (context) => {
// Handle verification failures
})
.onBeforeSettle(async (context) => {
// Validate before settlement
// Return { abort: true, reason: "..." } to cancel
})
.onAfterSettle(async (context) => {
// Track successful settlements
})
.onSettleFailure(async (context) => {
// Handle settlement failures
});
Network Identifiers
Networks use CAIP-2 format:
eip155:84532— Base Sepoliaeip155:8453— Base Mainnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1— Solana Devnetsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp— Solana Mainnet
Related Content
Looking for more? Check out our other typescript examples or browse by facilitator content.