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

# @meterlane/x402 SDK Reference — Payments & Middleware

> Install and use @meterlane/x402 to gate your APIs with x402 USDC payments and build agents that automatically pay those APIs with createAgentClient.

The `@meterlane/x402` package is Meterlane's core SDK. It ships two independent exports: a server-side middleware for protecting your API routes with USDC payments, and a MIT-licensed agent client that lets any script or AI agent pay those routes automatically. You can use either export on its own, or both together if you are building end-to-end.

## Scaffolding a new project

If you are starting from scratch, the fastest way to get a working Meterlane project is the scaffolding CLI:

```bash theme={null}
npx create-meterlane-app
```

This generates a Hono app pre-wired with `createCKMiddleware`, a funded test wallet script, and environment variable placeholders. If you are adding Meterlane to an existing project, follow the sections below.

***

## Agent client — `@meterlane/x402/client`

The agent client is a thin wrapper around the standard `fetch` API. When the server returns **HTTP 402**, it automatically signs an ERC-3009 USDC authorization and retries the request with payment headers. Your calling code needs no changes beyond swapping `fetch` for the wrapped version.

The client entry point is intentionally MIT-licensed so you can audit exactly what your agent signs before it spends funds.

### Install

<CodeGroup>
  ```bash npm theme={null}
  npm add @meterlane/x402
  ```

  ```bash yarn theme={null}
  yarn add @meterlane/x402
  ```

  ```bash pnpm theme={null}
  pnpm add @meterlane/x402
  ```
</CodeGroup>

### `createAgentClient(privateKey, network)`

```typescript theme={null}
import { createAgentClient } from "@meterlane/x402/client";
```

`createAgentClient` accepts a private key and an optional network identifier, and returns a `fetch`-compatible function. Drop it in wherever you currently call `fetch`.

| Parameter    | Type                              | Required | Description                                                    |
| ------------ | --------------------------------- | -------- | -------------------------------------------------------------- |
| `privateKey` | `Hex`                             | Yes      | 0x-prefixed 32-byte hex private key for the paying wallet      |
| `network`    | `"eip155:84532" \| "eip155:8453"` | No       | Network to pay on. Defaults to `"eip155:84532"` (Base Sepolia) |

**Return value:** A `fetch`-compatible async function. Call it exactly like `fetch(url, options)`.

#### Network options

| Identifier       | Chain                  | Facilitator             | Use when                                            |
| ---------------- | ---------------------- | ----------------------- | --------------------------------------------------- |
| `"eip155:84532"` | Base Sepolia (testnet) | Public `x402.org`       | Development, CI, and all sandbox demos              |
| `"eip155:8453"`  | Base mainnet           | Private, bring-your-own | Production — requires a mainnet-capable facilitator |

<Warning>
  The public `x402.org` facilitator **does not support Base mainnet**. Passing `"eip155:8453"` without a private mainnet facilitator will produce HTTP 500 errors. Use `"eip155:84532"` for all development and testing.
</Warning>

<Warning>
  Never embed your private key in source code. Read it from an environment variable such as `AGENT_PRIVATE_KEY`. Use a dedicated hot wallet with a limited USDC balance — do not reuse cold-storage or exchange keys.
</Warning>

### Paying the public demo route

The Meterlane public sandbox demo is available at `https://gateway.meterlane.app/gateway/demo/demo`. An unpaid `curl` returns **402**; a funded agent receives **200**.

```typescript theme={null}
import type { Hex } from "viem";
import { createAgentClient } from "@meterlane/x402/client";

const privateKey = process.env.AGENT_PRIVATE_KEY as Hex;
if (!privateKey?.startsWith("0x")) {
  throw new Error("Set AGENT_PRIVATE_KEY to a 0x-prefixed Base Sepolia funded key");
}

// Returns a fetch wrapper that handles 402 → sign → retry automatically
const paidFetch = createAgentClient(privateKey, "eip155:84532");

const res = await paidFetch(
  "https://gateway.meterlane.app/gateway/demo/demo",
  { method: "GET" }
);

console.log(res.status);           // 200 after successful payment
console.log(await res.text());     // response body from the upstream API
```

### Reading settlement metadata

After a successful payment the server attaches settlement information to the response headers. Check for these headers if you need a transaction hash or receipt:

```typescript theme={null}
const txHash =
  res.headers.get("PAYMENT-RESPONSE") ??
  res.headers.get("X-PAYMENT-RESPONSE");

console.log("Settlement:", txHash);
```

***

## Server middleware — `@meterlane/x402`

`createCKMiddleware` is a [Hono](https://hono.dev) middleware that gates one or more of your API routes behind x402 payments. When a caller sends a request without valid payment headers the middleware returns **HTTP 402** with the price and payment requirements. When payment is valid it settles on-chain and passes the request through to your handler.

### `createCKMiddleware(opts)`

```typescript theme={null}
import { createCKMiddleware } from "@meterlane/x402";
```

| Option             | Type                         | Required | Description                                                                      |
| ------------------ | ---------------------------- | -------- | -------------------------------------------------------------------------------- |
| `receiverAddress`  | `string`                     | Yes      | Ethereum address that receives USDC payments                                     |
| `routes`           | `RouteConfig[]`              | Yes      | Array of route configurations describing which paths are gated and at what price |
| `network`          | `string`                     | No       | `"base-mainnet"` for production; defaults to Base Sepolia                        |
| `facilitatorUrl`   | `string`                     | No       | URL of the x402 facilitator. Defaults to `https://x402.org/facilitator`          |
| `basePath`         | `string`                     | No       | Path prefix prepended to every route path (e.g. `"/gateway/my-org"`)             |
| `discoveryContext` | `GatewayDiscoveryContext`    | No       | Metadata for Meterlane Bazaar discovery on routes marked `discoverable: true`    |
| `onSettled`        | `(receipt) => Promise<void>` | No       | Callback invoked after every successful on-chain settlement                      |

**Return value:** A Hono `MiddlewareHandler`.

### Example: gating routes in a Hono app

```typescript theme={null}
import { Hono } from "hono";
import { createCKMiddleware } from "@meterlane/x402";

const app = new Hono();

app.use(
  "*",
  createCKMiddleware({
    receiverAddress: process.env.RECEIVER_ADDRESS!,
    routes: [
      {
        id: "weather",
        path: "/weather",
        priceUSD: 0.001,
        active: true,
        description: "Current weather for a given location",
      },
      {
        id: "sentiment",
        path: "/sentiment",
        priceUSD: 0.005,
        active: true,
        description: "Sentiment analysis for a block of text",
      },
    ],
  })
);

app.get("/weather", (c) => c.json({ temp: "72°F", condition: "Sunny" }));
app.get("/sentiment", (c) => c.json({ score: 0.82, label: "positive" }));

export default app;
```

### Tracking settlements with `onSettled`

The `onSettled` callback fires after every confirmed payment. Use it to record usage, trigger webhooks, or update a database.

```typescript theme={null}
createCKMiddleware({
  receiverAddress: process.env.RECEIVER_ADDRESS!,
  routes: [
    { id: "search", path: "/search", priceUSD: 0.002, active: true },
  ],
  onSettled: async ({ txHash, amountUSDC, fromAddress, routeId }) => {
    console.log(`Settled ${amountUSDC} USDC from ${fromAddress}`);
    console.log(`Route: ${routeId} — tx: ${txHash}`);

    // Example: write to your own database
    await db.payments.insert({ txHash, amountUSDC, fromAddress, routeId });
  },
});
```

The callback receives:

| Field         | Type     | Description                                 |
| ------------- | -------- | ------------------------------------------- |
| `txHash`      | `string` | On-chain transaction hash of the settlement |
| `amountUSDC`  | `string` | Amount settled in USDC (as a string)        |
| `fromAddress` | `string` | Paying wallet address                       |
| `routeId`     | `string` | The `id` from your `RouteConfig`            |
