Skip to main content
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:
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

npm add @meterlane/x402

createAgentClient(privateKey, network)

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.
ParameterTypeRequiredDescription
privateKeyHexYes0x-prefixed 32-byte hex private key for the paying wallet
network"eip155:84532" | "eip155:8453"NoNetwork 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

IdentifierChainFacilitatorUse when
"eip155:84532"Base Sepolia (testnet)Public x402.orgDevelopment, CI, and all sandbox demos
"eip155:8453"Base mainnetPrivate, bring-your-ownProduction — requires a mainnet-capable facilitator
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.
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.

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.
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:
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 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)

import { createCKMiddleware } from "@meterlane/x402";
OptionTypeRequiredDescription
receiverAddressstringYesEthereum address that receives USDC payments
routesRouteConfig[]YesArray of route configurations describing which paths are gated and at what price
networkstringNo"base-mainnet" for production; defaults to Base Sepolia
facilitatorUrlstringNoURL of the x402 facilitator. Defaults to https://x402.org/facilitator
basePathstringNoPath prefix prepended to every route path (e.g. "/gateway/my-org")
discoveryContextGatewayDiscoveryContextNoMetadata for Meterlane Bazaar discovery on routes marked discoverable: true
onSettled(receipt) => Promise<void>NoCallback invoked after every successful on-chain settlement
Return value: A Hono MiddlewareHandler.

Example: gating routes in a Hono app

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.
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:
FieldTypeDescription
txHashstringOn-chain transaction hash of the settlement
amountUSDCstringAmount settled in USDC (as a string)
fromAddressstringPaying wallet address
routeIdstringThe id from your RouteConfig