npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ledewire/x402-client

v0.2.0

Published

x402 fetch wrapper for Ledewire — handles ledewire-wallet scheme, buyer auth, and payment-signature construction

Readme

@ledewire/x402-client

npm License: MIT

Runtime-agnostic x402 fetch wrapper for the Ledewire payment network. Drop in as a replacement for fetch and it automatically handles 402 Payment Required challenges using the ledewire-wallet scheme — no payment code required in your agent or script.

Works in Node.js 18+, Deno, Cloudflare Workers, and any environment with web-standard fetch.

Install

npm install @ledewire/x402-client

Quick Start

import { createLedewireFetch } from '@ledewire/x402-client'

// Create a buyer API key at ledewire.com/settings/api-keys
const fetch = createLedewireFetch({
  key: process.env.LEDEWIRE_BUYER_KEY, // e.g. bktst_abc123
  secret: process.env.LEDEWIRE_BUYER_SECRET, // 64-char hex, shown once at creation
})

// That's it — payment is handled transparently
const res = await fetch('https://blog.example.com/posts/great-article')
const article = await res.json()

The full x402 handshake happens invisibly:

  1. First request hits the origin → 402 Payment Required with PAYMENT-REQUIRED header
  2. Client authenticates with buyer API key → gets buyer JWT
  3. Client constructs PAYMENT-SIGNATURE with JWT + contentId from the server's extension block
  4. Retries original request → 200 + content

What happens under the hood

Your code                     @ledewire/x402-client
─────────────────────────     ─────────────────────────────────────────────
fetch('https://origin/post')  → GET /post (no payment)
                              ← 402 + PAYMENT-REQUIRED header
                              → POST /v1/auth/login/buyer-api-key
                              ← buyer JWT (cached for token lifetime)
                              → GET /post + PAYMENT-SIGNATURE header
                              ← 200 + content
res ←─────────────────────────────────────────────────────────────────────

Configuration

import { createLedewireFetch } from '@ledewire/x402-client'
import type { LedewireFetchConfig } from '@ledewire/x402-client'

const fetch = createLedewireFetch({
  key: string,      // Buyer API key (e.g. bktst_abc123)
  secret: string,   // 64-char hex secret, shown once at creation

  // Optional — defaults to https://api.ledewire.com
  // Overridden automatically by the server's PAYMENT-REQUIRED extension block
  apiBase?: string,

  // Optional — provide a custom fetch (e.g. for proxies or testing)
  fetch?: typeof globalThis.fetch,
})

The apiBase is self-configuring: when the PAYMENT-REQUIRED response includes an extensions.ledewire-wallet.apiBase field (standard for Ledewire-gated content), that value takes precedence over any configured apiBase. This means the same client works for staging and production content without any configuration changes.

Transport adapters

Under the hood, createLedewireFetch is a one-liner built on two primitives that you can use directly when you need a different HTTP client:

| Export | Source | Purpose | | ----------------------- | ----------------------------- | --------------------------------------------- | | LedewirePaymentClient | @ledewire/x402-client | Holds credentials, builds PAYMENT-SIGNATURE | | wrapFetchWithPayment | @ledewire/x402-client | Wraps any fetch-compatible function | | wrapAxiosWithPayment | @ledewire/x402-client/axios | Adds an Axios response interceptor |

This mirrors the @x402/fetch / @x402/axios pattern from the x402 ecosystem — the client is separate from the transport.

Native fetch (default)

createLedewireFetch is the shorthand for this:

import { LedewirePaymentClient, wrapFetchWithPayment } from '@ledewire/x402-client'

const client = new LedewirePaymentClient({ key, secret })
const fetch = wrapFetchWithPayment(globalThis.fetch, client)

const res = await fetch('https://blog.example.com/posts/article')

Axios

Install axios then import from the subpath:

npm install axios
import axios from 'axios'
import { LedewirePaymentClient } from '@ledewire/x402-client'
import { wrapAxiosWithPayment } from '@ledewire/x402-client/axios'

const client = new LedewirePaymentClient({ key, secret })
const api = wrapAxiosWithPayment(axios.create(), client)

// Payment is handled transparently — same as fetch
const res = await api.get('https://blog.example.com/posts/article')
console.log(res.data)

The axios adapter attaches a response interceptor that catches 402 responses, calls client.buildPaymentSignature(), sets the PAYMENT-SIGNATURE header, and retries the original request.

Custom transports (ky, got, undici, …)

For any other HTTP client, call buildPaymentSignature directly inside your client's interceptor, hook, or middleware:

import { LedewirePaymentClient } from '@ledewire/x402-client'
import ky from 'ky'

const client = new LedewirePaymentClient({ key, secret })

const api = ky.create({
  hooks: {
    afterResponse: [
      async (request, _options, response) => {
        if (response.status !== 402) return response

        const header = response.headers.get('payment-required')
        if (!header) return response

        const sig = await client.buildPaymentSignature(header, request.url)
        return ky(request.url, {
          headers: { 'PAYMENT-SIGNATURE': sig },
        })
      },
    ],
  },
})

The PaymentSigner interface is what both built-in adapters depend on — you can also pass any object with a buildPaymentSignature method:

import type { PaymentSigner } from '@ledewire/x402-client'

const signer: PaymentSigner = {
  async buildPaymentSignature(header, url) {
    // custom implementation
  },
}

Getting a buyer API key

Create a key from a buyer account:

import { createClient } from '@ledewire/node'

const client = createClient()
await client.auth.loginWithEmail({ email, password })

const { key, secret } = await client.user.apiKeys.create({
  name: 'my-agent',
  spending_limit_cents: 5000, // $50 cap — optional
})
// Store secret immediately — it is never shown again

Or create one at ledewire.com/settings/api-keys.

Error handling

import {
  createLedewireFetch,
  InsufficientFundsError,
  NonceExpiredError,
  UnsupportedSchemeError,
  MalformedPaymentRequiredError,
} from '@ledewire/x402-client'
import { AuthError, LedewireError } from '@ledewire/core'

const fetch = createLedewireFetch({ key, secret })

try {
  const res = await fetch('https://blog.example.com/posts/article')
} catch (err) {
  if (err instanceof InsufficientFundsError) {
    // Wallet has insufficient funds — top up at ledewire.com/wallet
  } else if (err instanceof NonceExpiredError) {
    // Payment nonce expired — retry the fetch from the beginning
  } else if (err instanceof UnsupportedSchemeError) {
    // The 402 was not a ledewire-wallet challenge — pass through or handle
  } else if (err instanceof MalformedPaymentRequiredError) {
    // Server sent a malformed PAYMENT-REQUIRED — likely a server misconfiguration
  } else if (err instanceof LedewireError) {
    console.error(err.statusCode, err.message)
  }
}

| Error | Cause | | ------------------------------- | --------------------------------------------------------------- | | InsufficientFundsError | Wallet balance too low (server returned 422) | | NonceExpiredError | Payment nonce expired before retry — simply retry fetch() | | UnsupportedSchemeError | 402 response uses a non-ledewire-wallet scheme | | MalformedPaymentRequiredError | PAYMENT-REQUIRED header is invalid or missing required fields | | AuthError | Buyer API key credentials are invalid (401 on payment) | | LedewireError | All other Ledewire API errors — check .statusCode |

Token lifecycle

LedewireAuthManager caches the buyer JWT and re-authenticates automatically when the token is within 60 seconds of expiry. For agents with lifetimes shorter than a single token TTL (typically 30 minutes), authentication happens exactly once.

For long-running processes, the LedewireAuthManager instance inside the returned fetch handles re-authentication transparently on every payment attempt.

Runtime compatibility

This package uses only web-standard APIs: fetch, atob, btoa, Response, Headers, and URL. It has no Node.js-specific imports. It runs unchanged on:

  • Node.js 18+
  • Deno
  • Cloudflare Workers
  • Vercel Edge Runtime
  • Any other runtime with standard fetch

Related packages

  • @ledewire/node — full Ledewire API client for Node.js (buyer auth, wallet, purchases, merchant)
  • @ledewire/browser — Ledewire SDK for browser applications