# 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 payments](/build/x402.md).

> **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   | Optional. API key for facilitators that require one; the Radius facilitator does not, on mainnet or testnet |

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` means the facilitator failed or could not be reached. It does not mean the payment is invalid, and during settlement the payment may still have settled. Check before retrying or paying again; see [recover from failed or uncertain payments](/build/x402.md#recover-from-failed-or-uncertain-payments).

## 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 `erc2612`, v1 and v2; not payable by `radius-sdk` or `radius-cli`, so not a failover for Permit2 payments |
| 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 failed or unreachable                    | Check whether the payment settled before retrying |
| `"Permit expired"`               | Payment deadline passed                              | Client re-signs with fresh deadline               |

See [x402 payments — Troubleshooting](/build/x402.md#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:

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

## Related pages

* [x402 payments](/build/x402.md)
* [Contract addresses](/reference/contract-addresses.md)
* [Network and RPC](/reference/network.md)
* [Fees](/reference/fees.md)
* [JSON-RPC API](/reference/json-rpc/methods.md)
