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

# x402 Server — Monetizing APIs

> Accept x402 payments on your API endpoints with Chipi's paymaster

## Overview

The x402 server components let you monetize your API endpoints. Clients pay with USDC per request, and payments are settled gaslessly through Chipi's paymaster.

Two main components:

* **`X402Facilitator`** — Verifies payment signatures and settles via paymaster
* **`x402Middleware`** — Express middleware that handles the full 402 flow (also compatible with Express-like frameworks such as Hono)

## Express / Node.js

### Quick Setup

```typescript theme={null}
import express from "express";
import { ChipiServerSDK, x402Middleware } from "@chipi-stack/backend";

const sdk = new ChipiServerSDK({
  apiPublicKey: process.env.CHIPI_PUBLIC_KEY!,
  apiSecretKey: process.env.CHIPI_SECRET_KEY!,
});

const facilitator = sdk.createX402Facilitator();
const app = express();

// Protect an endpoint — requires 0.01 USDC per request
app.get("/premium",
  x402Middleware({
    facilitator,
    paymentConfig: {
      amount: "0.01",
      payTo: "0xYOUR_MERCHANT_ADDRESS",
      description: "Premium API access",
    },
  }),
  (req, res) => {
    // Payment was verified and settled
    res.json({
      data: "premium content",
      txHash: req.x402.txHash,
    });
  }
);

app.listen(3000);
```

### Middleware Behavior

1. **No `X-PAYMENT` header** → Returns 402 with `PAYMENT-REQUIRED` header
2. **Malformed header** → Returns 400
3. **Invalid payment** → Returns 402 with error reason
4. **Valid payment** → Settles via paymaster, attaches `req.x402`, calls `next()`

### Access Payment Info

After successful payment, `req.x402` contains:

```typescript theme={null}
{
  txHash: "0x...",        // Starknet transaction hash
  payment: { ... },       // Full PaymentPayload
  networkId: "starknet-mainnet"
}
```

### Verify-Only Mode

To verify payments without auto-settling (for custom settlement logic):

```typescript theme={null}
app.get("/custom",
  x402Middleware({
    facilitator,
    paymentConfig: { amount: "0.01", payTo: "0xADDRESS" },
    verifyOnly: true,  // Don't auto-settle
  }),
  async (req, res) => {
    // Payment is verified but not settled
    // Do your own settlement logic here
    const result = await facilitator.settle(req.x402.payment);
    res.json({ txHash: result.transactionHash });
  }
);
```

## Custom Nonce Store

By default, the facilitator uses an in-memory nonce store (resets on server restart). For production, plug in a persistent store:

### Redis Example

```typescript theme={null}
import Redis from "ioredis";

const redis = new Redis();

const facilitator = sdk.createX402Facilitator(undefined, {
  nonceStore: {
    has: async (nonce) => (await redis.exists(`x402:nonce:${nonce}`)) === 1,
    consume: async (nonce) => {
      // SET NX with 24h expiry — atomic check-and-consume
      const result = await redis.set(`x402:nonce:${nonce}`, "1", "EX", 86400, "NX");
      return result === "OK"; // true if newly set (not replayed)
    },
  },
});
```

### PostgreSQL Example

```typescript theme={null}
const facilitator = sdk.createX402Facilitator(undefined, {
  nonceStore: {
    has: async (nonce) => {
      const result = await db.query(
        "SELECT 1 FROM x402_nonces WHERE nonce = $1",
        [nonce]
      );
      return result.rows.length > 0;
    },
    consume: async (nonce) => {
      // INSERT … ON CONFLICT DO NOTHING returns rowCount 1 if inserted, 0 if duplicate.
      // This is atomic at the database level.
      const result = await db.query(
        "INSERT INTO x402_nonces (nonce, created_at) VALUES ($1, NOW()) ON CONFLICT DO NOTHING",
        [nonce]
      );
      return (result.rowCount ?? 0) > 0;
    },
  },
});
```

<Note>
  The `x402_nonces` table must enforce uniqueness on the `nonce` column:

  ```sql theme={null}
  CREATE TABLE x402_nonces (
    nonce TEXT PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT NOW()
  );
  ```

  For cleanup, run periodically: `DELETE FROM x402_nonces WHERE created_at < NOW() - INTERVAL '24 hours'`
</Note>

## Python — FastAPI

```python theme={null}
from fastapi import FastAPI, Depends, Request
from chipi_sdk import ChipiSDK, X402Facilitator, X402PaymentConfig
from chipi_sdk.x402_middleware import fastapi_x402_dependency

sdk = ChipiSDK(config)
facilitator = X402Facilitator(sdk, bearer_token="...")
payment_config = X402PaymentConfig(amount="0.01", pay_to="0xADDRESS")

app = FastAPI()

@app.get("/premium")
async def premium(
    request: Request,
    x402=Depends(fastapi_x402_dependency(facilitator, payment_config))
):
    return {
        "data": "premium content",
        "tx_hash": x402.get("tx_hash"),
    }
```

## Python — Flask

```python theme={null}
from flask import Flask, jsonify
from chipi_sdk import ChipiSDK, X402Facilitator, X402PaymentConfig
from chipi_sdk.x402_middleware import flask_x402_required

sdk = ChipiSDK(config)
facilitator = X402Facilitator(sdk, bearer_token="...")
payment_config = X402PaymentConfig(amount="0.01", pay_to="0xADDRESS")

app = Flask(__name__)

@app.route("/premium")
@flask_x402_required(facilitator, payment_config)
def premium():
    return jsonify({"data": "premium content"})
```

## Direct Facilitator Usage

For custom server frameworks or advanced use cases:

```typescript theme={null}
const facilitator = sdk.createX402Facilitator();

// Verify a payment (no settlement)
const verification = await facilitator.verify(paymentPayload);
if (!verification.isValid) {
  console.error("Invalid:", verification.invalidReason);
}

// Settle a payment (execute USDC transfer)
const settlement = await facilitator.settle(paymentPayload);
if (settlement.success) {
  console.log("Settled:", settlement.transactionHash);
}
```

## CORS Configuration

The middleware automatically skips `OPTIONS` (preflight) requests. Make sure your CORS setup includes the `X-PAYMENT` header:

```typescript theme={null}
import cors from "cors";

app.use(cors({
  exposedHeaders: ["Payment-Required"],
  allowedHeaders: ["X-PAYMENT", "Content-Type", "Authorization"],
}));
```
