Skip to content

cryptomotifs/cipher-x402-client

Repository files navigation

cipher-x402-client

Tiny TypeScript client for the x402 HTTP payment protocol v2 — a Linux Foundation-hosted open standard (April 2026) that turns HTTP 402 Payment Required into a machine-readable payment handshake.

  • Zero runtime deps. Uses native fetch and globalThis.crypto.
  • ESM + CJS dual build, TypeScript types included.
  • Chain-neutral. Signing is a callback — wire it to ethers, viem, or a remote signer. ethers is declared as an optional peer dep for the reference example, nothing more.
  • Node 18+ / modern browsers.

Install

npm install cipher-x402-client

Quick start

import {
  fetchPaid,
  selectPaymentMethod,
  buildPaymentHeader,
} from "cipher-x402-client";
import { Wallet } from "ethers";

const wallet = new Wallet(process.env.PRIVATE_KEY!);

const resp = await fetchPaid(
  "https://cipher-x402.vercel.app/premium/mev-deep-dive",
  {
    onPayment: async (parsed) => {
      const accept = selectPaymentMethod(parsed.accepts, {
        preferredChain: "eip155:8453", // Base
        maxAmountUsd: 0.05,
      });
      return await buildPaymentHeader(accept, wallet.address, async (authz, a) => {
        const domain = {
          name: "USDC",
          version: "2",
          chainId: 8453,
          verifyingContract: a.asset,
        };
        const types = {
          TransferWithAuthorization: [
            { name: "from", type: "address" },
            { name: "to", type: "address" },
            { name: "value", type: "uint256" },
            { name: "validAfter", type: "uint256" },
            { name: "validBefore", type: "uint256" },
            { name: "nonce", type: "bytes32" },
          ],
        };
        return await wallet.signTypedData(domain, types, authz);
      });
    },
  },
);

console.log(resp.status, await resp.text());

API

Symbol Purpose
parse402(response) Parse a Response / object / JSON string into a ParsedAccept. Throws NotA402Error on malformed input.
selectPaymentMethod(accepts, opts?) Pick the cheapest compatible payment method. opts: preferredChain, maxAmountUsd, allowedSchemes.
buildPaymentHeader(accept, signerAddress, signer, opts?) Build the base64-encoded X-Payment header. signer is a callback.
fetchPaid(url, { onPayment, ... }) fetch + automatic 402 retry with the X-Payment header set.

Every symbol is exported from the root:

import {
  parse402, selectPaymentMethod, buildPaymentHeader, fetchPaid,
  type ParsedAccept, type PaymentAccept, type ERC3009Authorization, type Signer,
  X402Error, NotA402Error, NoCompatibleMethodError, PaymentBuildError,
} from "cipher-x402-client";

Why is signing a callback?

x402 is scheme-agnostic: erc3009, exact, and future schemes (Solana SPL, Lightning, etc.) each have their own payload. Baking ethers into the package would pin a chain choice and drag in ~1 MB of code for anyone who only needs the wire format. Callback pattern keeps this package tiny.

A worked ethers v6 signer lives in the README above; a viem equivalent is ~10 lines.

Reference implementation / live demo

License

MIT.

About

Tiny TypeScript client for the x402 HTTP payment protocol v2 (Linux Foundation). Zero deps, native fetch, ESM + CJS.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors