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:
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
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.
| 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 |
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
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";
| 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
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:
| 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 |