> ## Documentation Index
> Fetch the complete documentation index at: https://docs.houdiniswap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# x402 Payments

> Pay-per-request API access using USDC stablecoin payments

# x402: Pay-Per-Request API Access

HoudiniSwap Partner API v2 supports the [x402 payment protocol](https://docs.cdp.coinbase.com/x402/welcome) as an alternative to traditional API key authentication. With x402, you pay for each API request using USDC on supported EVM chains — no account registration or API key required.

## How It Works

The x402 protocol uses the HTTP `402 Payment Required` status code to enable pay-per-request access:

```
Client                    HoudiniSwap API              Facilitator
  |                            |                           |
  |  1. GET /v2/tokens         |                           |
  |--------------------------->|                           |
  |  2. 402 Payment Required   |                           |
  |    (PAYMENT-REQUIRED header)|                          |
  |<---------------------------|                           |
  |                            |                           |
  |  3. Sign USDC authorization|                           |
  |  (EIP-3009, gasless)       |                           |
  |                            |                           |
  |  4. GET /v2/tokens         |                           |
  |    (PAYMENT-SIGNATURE hdr) |                           |
  |--------------------------->|                           |
  |                            |  5. Verify & settle       |
  |                            |-------------------------->|
  |                            |  6. Settlement confirmed  |
  |                            |<--------------------------|
  |  7. 200 OK (data)          |                           |
  |<---------------------------|                           |
```

1. Client makes a request without authentication
2. Server responds with `402` and a `PAYMENT-REQUIRED` header containing payment instructions
3. Client signs a USDC `transferWithAuthorization` (EIP-3009) — **no gas required**
4. Client retries the request with the signed payment in the `PAYMENT-SIGNATURE` header
5. Server forwards the payment to the facilitator for on-chain verification and settlement
6. Facilitator confirms the USDC transfer
7. Server returns the requested data

## Supported Networks

| Network        | CAIP-2 ID     | USDC Contract                                |
| -------------- | ------------- | -------------------------------------------- |
| Base (default) | `eip155:8453` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |

Additional EVM networks (Ethereum, Polygon, Arbitrum) can be enabled — contact us for availability.

## Pricing

Requests are priced by operation type in USDC:

| Operation    | Price (USDC) | Endpoints                                                                                                                                             |
| ------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Read**     | \$0.0001     | `GET /tokens`, `GET /chains`, `GET /swaps`, `GET /minMax`, `GET /rateLimits`, `POST /dex/approve`, `POST /dex/allowance`, `POST /dex/chainSignatures` |
| **Quote**    | \$0.001      | `GET /quotes`, `GET /quotes/byChainAddress`                                                                                                           |
| **Exchange** | \$0.01       | `POST /exchanges`, `POST /exchanges/multi`, `GET /exchanges/multi/{id}/tx`, `POST /dex/confirmTx`                                                     |
| **Status**   | \$0.0001     | `GET /exchanges/multi/{id}`, `GET /orders`, `GET /orders/{id}`                                                                                        |

<Note>
  `GET /v2/health` and `GET /v2/openapi.json` are always free and do not require payment or authentication.
</Note>

## Rate Limits

x402 payers are rate-limited to **60 requests per minute** per payer address. This is separate from API key rate limits.

## x402 vs API Key Authentication

| Feature               | x402                       | API Key                  |
| --------------------- | -------------------------- | ------------------------ |
| Registration required | No                         | Yes                      |
| Pay model             | Per-request                | Subscription/tier        |
| Authentication        | USDC payment               | `Authorization` header   |
| Rate limits           | 60 req/min per address     | Tier-based               |
| Best for              | Agents, bots, ad-hoc usage | High-volume integrations |

When both are available, API key authentication takes priority. If a request includes an `Authorization` header (full API key access) or a `partner-id` header (public read-only partner access), the x402 payment flow is bypassed entirely.

## Quick Start

### Prerequisites

* An EVM wallet with USDC on a supported network
* Node.js 18+ (for the JavaScript client)
* USDC on Base (amounts are tiny — a full exchange flow costs \~\$0.012 total)

### 1. Install Dependencies

```bash theme={null}
npm install @x402/fetch @x402/evm viem
```

### 2. Create a Payment Client

```typescript theme={null}
import { x402Client, x402HTTPClient } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

// Create signer from your wallet's private key
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);

// Create x402 client and register EVM payment scheme
const client = new x402Client();
registerExactEvmScheme(client, { signer });
const httpClient = new x402HTTPClient(client);
```

### 3. Make Paid API Requests

```typescript theme={null}
const BASE_URL = "https://api-partner.houdiniswap.com";

const x402Fetch = async (url: string, options: RequestInit = {}) => {
  // Initial request
  const res = await fetch(url, options);
  if (res.status !== 402) return res;

  // Parse payment requirements from 402 response
  const paymentRequired = httpClient.getPaymentRequiredResponse(
    (name) => res.headers.get(name),
    undefined,
  );

  // Sign the USDC payment (gasless EIP-3009)
  const payload = await client.createPaymentPayload(paymentRequired);
  const paymentHeaders = httpClient.encodePaymentSignatureHeader(payload);

  // Retry with payment proof
  return fetch(url, {
    ...options,
    headers: { ...options.headers, ...paymentHeaders },
  });
};

// Get tokens — automatically handles 402 → pay → retry
const response = await x402Fetch(`${BASE_URL}/v2/tokens?term=BTC`);
const data = await response.json();
console.log(data.tokens);
```

### 4. Check Payment Receipt

Successful paid responses include a `payment-response` header:

```typescript theme={null}
const paymentResponse = response.headers.get("payment-response");
if (paymentResponse) {
  const receipt = JSON.parse(Buffer.from(paymentResponse, "base64").toString());
  console.log(receipt);
  // {
  //   "success": true,
  //   "transaction": "0xabc...def",
  //   "network": "eip155:8453",
  //   "payer": "0x..."
  // }
}
```

## Full Exchange Flow Example

This example demonstrates a complete swap flow using x402 payments:

```typescript theme={null}
import { x402Client, x402HTTPClient } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
registerExactEvmScheme(client, { signer });
const httpClient = new x402HTTPClient(client);

const BASE = "https://api-partner.houdiniswap.com/v2";

const x402Fetch = async (url: string, options: RequestInit = {}) => {
  const res = await fetch(url, options);
  if (res.status !== 402) return res;
  const pr = httpClient.getPaymentRequiredResponse((n) => res.headers.get(n), undefined);
  const payload = await client.createPaymentPayload(pr);
  const headers = httpClient.encodePaymentSignatureHeader(payload);
  return fetch(url, { ...options, headers: { ...options.headers, ...headers } });
};

// Step 1: Look up tokens ($0.0001 each)
const btcRes = await x402Fetch(`${BASE}/tokens?term=BTC&hasCex=true`);
const btcData = await btcRes.json();
const btcToken = btcData.tokens.find((t: any) => t.chain === "bitcoin");

const ethRes = await x402Fetch(`${BASE}/tokens?term=ETH&hasCex=true`);
const ethData = await ethRes.json();
const ethToken = ethData.tokens.find((t: any) => t.chain === "ethereum");

// Step 2: Get a quote ($0.001)
const quoteRes = await x402Fetch(
  `${BASE}/quotes?from=${btcToken.id}&to=${ethToken.id}&amount=0.01`
);
const quoteData = await quoteRes.json();
const quote = quoteData.quotes[0];
console.log(`Quote: ${quote.amountOut} ETH`);

// Step 3: Create exchange ($0.01)
const exchangeRes = await x402Fetch(`${BASE}/exchanges`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    quoteId: quote.quoteId,
    addressTo: "0xYourEthAddress...",
  }),
});
const exchange = await exchangeRes.json();
console.log(`Order: ${exchange.houdiniId}, deposit to: ${exchange.depositAddress}`);

// Step 4: Poll status ($0.0001 each)
const checkStatus = async () => {
  const res = await x402Fetch(`${BASE}/orders/${exchange.houdiniId}`);
  return res.json();
};

let order = await checkStatus();
const TERMINAL = ["FINISHED", "FAILED", "EXPIRED", "REFUNDED", "DELETED"];
while (!TERMINAL.includes(order.statusLabel)) {
  await new Promise((r) => setTimeout(r, 30000));
  order = await checkStatus();
  console.log(`Status: ${order.statusLabel}`);
}
```

<Warning>
  Each x402 payment is an on-chain USDC transfer. Allow sufficient time between rapid sequential requests to avoid transaction failures from nonce collisions. For high-frequency access, consider using [API key authentication](/developer-hub/getting-started/authentication) instead.
</Warning>

## Headers

### x402 Protocol Headers

These headers are set by the x402 SDK and carry the payment data:

| Header              | Direction      | Description                                                                    |
| ------------------- | -------------- | ------------------------------------------------------------------------------ |
| `PAYMENT-REQUIRED`  | Response (402) | Base64-encoded JSON with payment instructions (price, network, payTo address)  |
| `PAYMENT-SIGNATURE` | Request        | Base64-encoded signed payment payload (client sends this on the retry request) |
| `payment-response`  | Response (200) | Base64-encoded settlement receipt (transaction hash, payer, network)           |

### CORS Headers

HoudiniSwap adds the x402 headers to CORS allow/expose lists so browser-based clients can access them:

| Header                          | Value added                                                       |
| ------------------------------- | ----------------------------------------------------------------- |
| `Access-Control-Allow-Headers`  | `X-PAYMENT` (allows clients to send payment headers)              |
| `Access-Control-Expose-Headers` | `X-PAYMENT-RESPONSE` (allows clients to read settlement receipts) |

<Note>
  The CORS header names (`X-PAYMENT`, `X-PAYMENT-RESPONSE`) are SDK-level aliases. The actual protocol headers your code reads/writes are `PAYMENT-REQUIRED`, `PAYMENT-SIGNATURE`, and `payment-response` as listed above.
</Note>

## Payment Required Response Format

The `PAYMENT-REQUIRED` header decodes to:

```json theme={null}
{
  "x402Version": 2,
  "error": "Payment required",
  "resource": {
    "url": "https://api-partner.houdiniswap.com/v2/tokens",
    "description": "HoudiniSwap API - GET /tokens",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "100",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x...",
      "maxTimeoutSeconds": 300,
      "extra": {
        "name": "USDC",
        "version": "2"
      }
    }
  ]
}
```

<Note>
  The `amount` field is in USDC atomic units (6 decimals). `100` = \$0.0001 USDC.
</Note>

## Other Languages

The x402 protocol has official client libraries for multiple languages:

* **Python**: [`x402`](https://pypi.org/project/x402/) with `httpx` or `requests`
* **Go**: [`github.com/coinbase/x402/go`](https://github.com/coinbase/x402/tree/main/go)
* **Axios** (Node.js): [`@x402/axios`](https://www.npmjs.com/package/@x402/axios)

See the [x402 Quickstart for Buyers](https://docs.cdp.coinbase.com/x402/quickstart-for-buyers) for setup instructions in each language.

## Error Handling

| Scenario                     | Response                            | Action                            |
| ---------------------------- | ----------------------------------- | --------------------------------- |
| No auth header, x402 enabled | `402` with `PAYMENT-REQUIRED`       | Sign payment and retry            |
| Payment signature invalid    | `402` with `payment-response` error | Check signing key and payload     |
| Facilitator unavailable      | `503 Service Unavailable`           | Retry later or use API key auth   |
| Rate limit exceeded (x402)   | `429 Too Many Requests`             | Wait and retry (60 req/min limit) |
| API key present              | Normal auth flow                    | x402 is bypassed entirely         |

## Further Reading

* [x402 Protocol Overview](https://docs.cdp.coinbase.com/x402/welcome) — Official protocol specification
* [x402 Quickstart for Buyers](https://docs.cdp.coinbase.com/x402/quickstart-for-buyers) — Client setup in all languages
* [x402 Network Support](https://docs.cdp.coinbase.com/x402/network-support) — Supported chains and assets
