x402 facilitator API
A facilitator is a service that verifies x402 payment signatures and settles them on-chain. This page documents the facilitator HTTP endpoints, TypeScript types, headers, status codes, and endorsed facilitators for Radius.
For integration patterns and settlement strategies, see x402 integration.
Endpoints
GET /supported
Returns the facilitator's supported networks, schemes, and signer addresses.
Parameters: None
Response body:| Field | Type | Description |
|---|---|---|
kinds | array | List of supported payment kinds |
kinds[].x402Version | number | Protocol version (1 or 2) |
kinds[].scheme | string | Payment scheme (for example, exact) |
kinds[].network | string | CAIP-2 network identifier |
kinds[].extra | object | Scheme-specific metadata |
kinds[].extra.assetTransferMethod | string | Transfer method (for example, erc2612) |
kinds[].extra.name | string | ERC-2612 permit domain name |
kinds[].extra.version | string | ERC-2612 permit domain version |
extensions | array | Supported protocol extensions |
signers | object | Map of CAIP-2 patterns to signer addresses |
{
"kinds": [
{
"x402Version": 2,
"scheme": "exact",
"network": "eip155:723487",
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
},
{
"x402Version": 2,
"scheme": "exact",
"network": "eip155:72344",
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
}
],
"extensions": [],
"signers": {
"eip155:*": ["0xdeE710bB6a3b652C35B5cB74E7bdb03EE1F641E6"]
}
}curl https://x402.stablecoin.xyz/supportedPOST /verify
Verifies a payment signature without settling on-chain. Use this endpoint to validate payment data before committing to settlement.
Request body:The server passes the decoded PAYMENT-SIGNATURE value directly as paymentPayload and adds a paymentRequirements object built from its own config:
| Field | Type | Description |
|---|---|---|
x402Version | number | Protocol version (2) |
paymentPayload | object | The decoded client payload from the PAYMENT-SIGNATURE header |
paymentPayload.x402Version | number | Protocol version (2) |
paymentPayload.resource | object | (Optional) Resource info echoed from the 402 response |
paymentPayload.accepted | object | The payment method the client selected |
paymentPayload.accepted.scheme | string | Payment scheme (for example, exact) |
paymentPayload.accepted.network | string | CAIP-2 network identifier |
paymentPayload.accepted.amount | string | Payment amount in raw token units |
paymentPayload.accepted.asset | string | ERC-20 token contract address |
paymentPayload.accepted.payTo | string | Recipient address |
paymentPayload.accepted.maxTimeoutSeconds | number | Maximum time the payment is valid |
paymentPayload.accepted.extra | object | Scheme-specific metadata |
paymentPayload.payload | object | Signed authorization data |
paymentPayload.payload.signature | string | Single 65-byte hex-encoded signature |
paymentPayload.payload.authorization | object | EIP-2612 permit fields |
paymentPayload.payload.authorization.from | string | Payer address |
paymentPayload.payload.authorization.to | string | Spender address (the settlement wallet) |
paymentPayload.payload.authorization.value | string | Payment amount in raw token units |
paymentPayload.payload.authorization.validAfter | string | Earliest valid timestamp |
paymentPayload.payload.authorization.validBefore | string | Latest valid timestamp |
paymentPayload.payload.authorization.nonce | string | Unique nonce for replay protection |
paymentPayload.extensions | object | (Optional) Protocol extensions data |
paymentRequirements | object | Expected payment parameters from the server config |
paymentRequirements.scheme | string | Payment scheme (for example, exact) |
paymentRequirements.network | string | CAIP-2 network identifier |
paymentRequirements.amount | string | Required amount in raw token units |
paymentRequirements.asset | string | ERC-20 token contract address |
paymentRequirements.payTo | string | Expected recipient address |
paymentRequirements.maxTimeoutSeconds | number | Maximum time the payment is valid |
paymentRequirements.extra | object | Token permit domain metadata |
| Field | Type | Description |
|---|---|---|
isValid | boolean | true if the payment signature and balance check pass |
payer | string | Address of the payer |
invalidReason | string | (Optional) Machine-readable reason for failure if isValid is false |
invalidMessage | string | (Optional) Human-readable failure message |
extensions | object | (Optional) Protocol extensions data |
curl -X POST https://x402.stablecoin.xyz/verify \
-H "Content-Type: application/json" \
-d '{
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
},
"payload": {
"signature": "{{SIGNATURE}}",
"authorization": {
"from": "{{PAYER_ADDRESS}}",
"to": "{{MERCHANT_ADDRESS}}",
"value": "100",
"validAfter": "0",
"validBefore": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": "{{NONCE}}"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": { "name": "Stable Coin", "version": "1" }
}
}'{ "isValid": true, "payer": "{{PAYER_ADDRESS}}" }{ "isValid": false, "invalidReason": "insufficient_funds", "invalidMessage": "Payer balance is below the required amount", "payer": "{{PAYER_ADDRESS}}" }POST /settle
Settles a verified payment on-chain. The request body matches the /verify endpoint. On success, the facilitator submits the permit and transfer transactions to Radius and returns the transaction hash.
Request body: Same as POST /verify. The facilitator splits the signature into v, r, s internally when calling the on-chain permit() function.
| Field | Type | Description |
|---|---|---|
success | boolean | true if settlement completed |
transaction | string | On-chain transaction hash (empty string if failed) |
network | string | CAIP-2 network identifier where settlement occurred |
payer | string | Address of the payer |
errorReason | string | (Optional) Machine-readable reason for failure if success is false |
errorMessage | string | (Optional) Human-readable failure message |
extensions | object | (Optional) Protocol extensions data |
curl -X POST https://x402.stablecoin.xyz/settle \
-H "Content-Type: application/json" \
-d '{
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
},
"payload": {
"signature": "{{SIGNATURE}}",
"authorization": {
"from": "{{PAYER_ADDRESS}}",
"to": "{{MERCHANT_ADDRESS}}",
"value": "100",
"validAfter": "0",
"validBefore": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": "{{NONCE}}"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": { "name": "Stable Coin", "version": "1" }
}
}'{
"success": true,
"transaction": "0x...",
"network": "eip155:723487",
"payer": "{{PAYER_ADDRESS}}"
}{
"success": false,
"errorReason": "insufficient_funds",
"errorMessage": "Payer balance is below the required amount",
"transaction": "",
"network": "eip155:723487",
"payer": "{{PAYER_ADDRESS}}"
}GET /health
Returns the facilitator's health status.
Parameters: None
Example request:curl https://x402.stablecoin.xyz/healthTypeScript types
X402Config
Configuration for x402 payment gating on a server or gateway.
interface X402Config {
/** ERC-20 token contract address */
asset: string;
/** CAIP-2 chain identifier, e.g. "eip155:723487" */
network: string;
/** Wallet address that receives payments */
payTo: string;
/** Facilitator service base URL */
facilitatorUrl: string;
/** Payment amount in raw token units (e.g. "100" = 0.0001 SBC with 6 decimals) */
amount: string;
/** Optional API key for the facilitator */
facilitatorApiKey?: string;
/** ERC-2612 permit domain name (default: "Stable Coin") */
tokenName?: string;
/** ERC-2612 permit domain version (default: "1") */
tokenVersion?: string;
/** HTTP header carrying the payment (default: "PAYMENT-SIGNATURE") */
paymentHeader?: string;
}PaymentRequired
The object encoded in the PAYMENT-REQUIRED header when a resource requires payment.
interface PaymentRequired {
x402Version: number;
error?: string;
resource: {
url: string;
description?: string;
mimeType?: string;
};
accepts: PaymentRequirementsItem[];
extensions?: Record<string, unknown>;
}PaymentRequirementsItem
A single accepted payment method within PaymentRequired.accepts.
interface PaymentRequirementsItem {
scheme: string;
network: string;
amount: string;
asset: string;
payTo: string;
maxTimeoutSeconds: number;
extra: Record<string, unknown>;
}PaymentOutcome
All possible outcomes of a payment flow, used by server-side middleware to determine HTTP responses.
type PaymentOutcome =
| { status: 'no-payment'; requirements: PaymentRequired }
| { status: 'invalid-header' }
| { status: 'verify-failed'; detail: any }
| { status: 'verify-unreachable'; detail: string }
| { status: 'settle-failed'; detail: any }
| { status: 'settle-unreachable'; detail: string }
| {
status: 'settled';
transaction: string | undefined;
payer: string;
network: string;
verifyMs: number;
settleMs: number;
totalMs: number;
}
| { status: 'settle-pending'; verifyMs: number; totalMs: number };HTTP headers
| Header | Direction | Description |
|---|---|---|
PAYMENT-REQUIRED | Response | Base64-encoded PaymentRequired object returned in a 402 response |
PAYMENT-SIGNATURE | Request | Base64-encoded payment payload sent by the client |
PAYMENT-RESPONSE | Response | Base64-encoded SettleResponse object returned on a 200 after settlement |
x-api-key | Request | API key for facilitator authentication (required for mainnet) |
The client reads the PAYMENT-REQUIRED header from the 402 response, constructs a signed payment, Base64-encodes it, and attaches it as PAYMENT-SIGNATURE on the retry request. On success, the server returns a PAYMENT-RESPONSE header containing the settlement details.
Status code mapping
Each PaymentOutcome status maps to an HTTP status code returned by the server middleware:
PaymentOutcome status | HTTP status | Meaning |
|---|---|---|
no-payment | 402 | No PAYMENT-SIGNATURE header present |
invalid-header | 400 | Malformed PAYMENT-SIGNATURE header |
verify-failed | 402 | Signature or balance check failed |
verify-unreachable | 502 | Facilitator /verify endpoint unreachable |
settle-failed | 402 | On-chain settlement rejected |
settle-unreachable | 502 | Facilitator /settle endpoint unreachable |
settle-pending | 200 | Async settlement fired, resource served |
settled | 200 | Payment confirmed on-chain, resource served |
Facilitators supporting Radius
| Facilitator | URL | Radius networks | Notes |
|---|---|---|---|
| Stablecoin.xyz | https://x402.stablecoin.xyz | Mainnet + Testnet | SBC via EIP-2612, v1 and v2 |
| FareSide | https://facilitator.x402.rs | Testnet | Free (testnet only) |
| Middlebit | https://middlebit.com | Mainnet | Middleware layer, uses Stablecoin.xyz for settlement |
Network reference
| Property | Mainnet | Testnet |
|---|---|---|
| Chain ID | 723487 | 72344 |
| CAIP-2 | eip155:723487 | eip155:72344 |
| SBC token | 0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb | 0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb |
| SBC decimals | 6 | 6 |
| Permit domain name | Stable Coin | Stable Coin |
| Permit domain version | 1 | 1 |
Raw token units use 6 decimals. A value of "100" equals 0.0001 SBC. A value of "1000000" equals 1 SBC.