---
title: x402 facilitator API
description: Reference for the x402 facilitator endpoints used for payment verification and settlement on Radius.
---
# x402 facilitator API

*Payment verification and settlement endpoints*


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](/developer-resources/x402-integration).

:::tip[Migrating from x402 v1?]
The v2 protocol changes header names, network identifiers, and package structure. See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2) for a complete walkthrough.
:::

## 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: `permit2` (Radius) or `erc2612` (Stablecoin.xyz)                                |
| `kinds[].extra.name`                | `string` | ERC-2612 permit domain name                                                                      |
| `kinds[].extra.version`             | `string` | ERC-2612 permit domain version                                                                   |
| `extensions`                        | `array`  | Supported protocol extensions (for example, `eip2612GasSponsoring` for gasless Permit2 approval) |
| `signers`                           | `object` | Map of CAIP-2 patterns to signer addresses                                                       |

**Example response (Radius mainnet facilitator):**

```json
{
  "kinds": [
    {
      "x402Version": 2,
      "scheme": "exact",
      "network": "eip155:723487",
      "extra": {
        "assetTransferMethod": "permit2",
        "name": "Stable Coin",
        "version": "1"
      }
    }
  ],
  "extensions": ["eip2612GasSponsoring"],
  "signers": {}
}
```

The Radius testnet facilitator (`https://facilitator.testnet.radiustech.xyz/supported`) returns an equivalent response with `"network": "eip155:72344"`.

`assetTransferMethod` is `"permit2"` for the Radius facilitator or `"erc2612"` for Stablecoin.xyz. The `"eip2612GasSponsoring"` extension means the facilitator handles the one-time Permit2 approval gaslessly if the payer hasn't already approved the Permit2 contract.

**Example request:**

```bash
curl https://facilitator.radiustech.xyz/supported
```

---

### `POST /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 (for EIP-2612 flows: the settlement wallet; for Permit2 flows: the `x402ExactPermit2Proxy`) |
| `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                                                                                |

When using a Permit2-based facilitator, the payment payload uses `permit2Authorization` instead of `authorization`, with different fields (`permitted`, `spender`, `witness`). The `/verify` and `/settle` request format is the same — the facilitator interprets the payload based on the `assetTransferMethod`. See the [x402 exact EVM scheme spec](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) for the Permit2 payload structure.

**Response body:**

| 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                                    |

**Example request (EIP-2612 payload format):**

The example below uses the EIP-2612 `authorization` format. For the Permit2 `permit2Authorization` format used with the Radius facilitator, see the [x402 exact EVM scheme spec](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md).

```bash
curl -X POST https://facilitator.radiustech.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" }
    }
  }'
```

**Example response (success):**

```json
{ "isValid": true, "payer": "{{PAYER_ADDRESS}}" }
```

**Example response (failure):**

```json
{ "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`](#post-verify). For EIP-2612 flows, the facilitator splits the signature into `v`, `r`, `s` internally when calling the on-chain `permit()` function. For Permit2 flows, the facilitator forwards the signature to the `x402ExactPermit2Proxy` contract.

**Response body:**

| 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                                    |

**Example request (EIP-2612 payload format):**

```bash
curl -X POST https://facilitator.radiustech.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" }
    }
  }'
```

**Example response (success):**

```json
{
  "success": true,
  "transaction": "0x...",
  "network": "eip155:723487",
  "payer": "{{PAYER_ADDRESS}}"
}
```

**Example response (failure):**

```json
{
  "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:**

```bash
curl https://facilitator.radiustech.xyz/health
```

## TypeScript types

### `X402Config`

Configuration for x402 payment gating on a server or gateway.

```typescript
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.

```typescript
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`.

```typescript
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.

```typescript
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 |


> **📝 Note:** A `502` response indicates the facilitator service is down, not that the payment is invalid. Clients can retry against an alternate facilitator.

## Facilitators supporting Radius

| Facilitator              | URL                                                                                                 | Radius networks   | Notes                                                |
| ------------------------ | --------------------------------------------------------------------------------------------------- | ----------------- | ---------------------------------------------------- |
| **Radius** (recommended) | Mainnet: `https://facilitator.radiustech.xyz` Testnet: `https://facilitator.testnet.radiustech.xyz` | Mainnet + Testnet | First-party, Permit2 + gas sponsoring, v2            |
| Stablecoin.xyz           | `https://x402.stablecoin.xyz`                                                                       | Mainnet + Testnet | SBC via EIP-2612, v1 and v2                          |
| 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.

## Troubleshooting

| Error                            | Cause                                                | Action                                           |
| -------------------------------- | ---------------------------------------------------- | ------------------------------------------------ |
| `"No available wallets in pool"` | Facilitator settlement wallets temporarily exhausted | Retry after 1-2s; contact operator if persistent |
| HTTP `502`                       | Facilitator unreachable                              | Retry or switch to alternate facilitator         |
| `"Permit expired"`               | Payment deadline passed                              | Client re-signs with fresh deadline              |

See [x402 integration — Troubleshooting](/developer-resources/x402-integration#troubleshooting) for details.

## Note for facilitator operators

The Radius facilitator does not currently expose `permit2Address` or `x402Permit2ProxyAddress` in the `/supported` response. Including these as optional fields in `extra` for `permit2` entries would make integration self-documenting, removing the need for integrators to look up canonical addresses:

```json
"extra": {
  "assetTransferMethod": "permit2",
  "permit2Address": "0x000000000022D473030F116dDEE9F6B43aC78BA3",
  "x402Permit2ProxyAddress": "0x402085c248EeA27D92E8b30b2C58ed07f9E20001",
  "name": "Stable Coin",
  "version": "1"
}
```

## Related pages

- [x402 integration](/developer-resources/x402-integration)
- [Contract addresses](/developer-resources/contract-addresses)
- [Network and RPC](/developer-resources/network-configuration)
- [Fees](/developer-resources/fees)
- [JSON-RPC API](/developer-resources/json-rpc-api)
