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

tokenbanking

v0.1.2

Published

TokenBanking SDK for Node.js and Bun — OpenAI-compatible client with marketplace price caps and automatic fallback.

Readme

TokenBanking SDK

One API key, every model, always routed to the cheapest available supplier. Streaming, tool calling, retries and timeouts all work out of the box, and you can cap what you're willing to pay per request.

Works with Node.js ≥ 20 or Bun.

Get an API key

  1. Sign in at https://tokenbanking.aimake.website/.
  2. Load credits under Dashboard → Credits (USDC on Arc, or Stripe).
  3. Create a key under Dashboard → API keys and copy the tb_… token. Treat it like a password; you can copy it again from the key list.
export TOKENBANKING_API_KEY="tb_…"

Installation

npm install tokenbanking
# or
bun add tokenbanking

Quickstart

import TB from "tokenbanking";

// apiKey defaults to $TOKENBANKING_API_KEY, baseURL to the hosted router.
const tb = new TB.Client();

const response = await tb.chat.completions.create({
  model: "minimax/minimax-m2.7",
  messages: [{ role: "user", content: "Explain USDC in two sentences." }],
  maxPrice: { input: 1.0, output: 1.0 }, // USD per 1M tokens
});

console.log(response.choices[0].message.content);

Model ids are the vendor-prefixed ids listed on the Models pageminimax/minimax-m2.7, deepseek/deepseek-v3.2, z-ai/glm-5.2, and so on.

Configuration is picked up from the environment when not passed explicitly:

| Env var | Purpose | Default | | --- | --- | --- | | TOKENBANKING_API_KEY | Your TokenBanking consumer key | — | | TOKENBANKING_BASE_URL | Router base URL | https://tb-proxy.aimake.website/v1 |

Price caps (maxPrice)

maxPrice caps what you're willing to pay, in USD per 1M tokens. Anything you leave out is unlimited. Suppliers above your cap are skipped; if no supplier fits, the request fails with 402 instead of overpaying.

const chat = await tb.chat.completions.create({
  model: "minimax/minimax-m2.7",
  messages: [{ role: "user", content: "Hello!" }],
  maxPrice: { input: 1.0 }, // output & cached: no limit
});

The SDK lifts maxPrice out of the request body into x-tb-max-price-* headers, so it never reaches the upstream provider.

TypeScript

maxPrice is an extension to the standard chat-completions body, so TypeScript needs to be told about it — wrap the params in WithMaxPrice<…>:

import TB, { type WithMaxPrice } from "tokenbanking";
import type { ChatCompletionCreateParamsNonStreaming } from "openai/resources/chat/completions";

const params: WithMaxPrice<ChatCompletionCreateParamsNonStreaming> = {
  model: "minimax/minimax-m2.7",
  messages: [{ role: "user", content: "Hello!" }],
  maxPrice: { input: 1.0, output: 1.0 },
};

const chat = await tb.chat.completions.create(params);

On responses.create it is typed natively, so no wrapper is needed there.

Fallback

Pass any OpenAI-compatible client as fallback. If the router is unreachable or returns 402 / 408 / 429 / 5xx, the same request is transparently replayed against the fallback with its own base URL and API key:

import TB from "tokenbanking";
import OpenAI from "openai";

const tb = new TB.Client({
  fallback: new OpenAI({ apiKey: process.env.OPENAI_API_KEY }),
});

Streaming

const stream = await tb.chat.completions.create({
  model: "minimax/minimax-m2.7",
  messages: [{ role: "user", content: "Write a haiku about foxes." }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

Tool calling

const response = await tb.chat.completions.create({
  model: "minimax/minimax-m2.7",
  messages: [{ role: "user", content: "What's the weather in São Paulo?" }],
  tools: [
    {
      type: "function",
      function: {
        name: "get_weather",
        description: "Get the current weather for a city",
        parameters: {
          type: "object",
          properties: { city: { type: "string" } },
          required: ["city"],
        },
      },
    },
  ],
});

for (const call of response.choices[0].message.tool_calls ?? []) {
  if (call.type !== "function") continue;
  console.log(call.function.name, JSON.parse(call.function.arguments));
}

Feed results back as role: "tool" messages, exactly as with openai-node.

Responses API

tb.responses.create is a shim over /v1/chat/completions (the router is chat-completions native):

const response = await tb.responses.create({
  model: "minimax/minimax-m2.7",
  input: "Complete the sentence: 'The quick brown fox jumps over the'",
  maxPrice: { input: 1.0, output: 1.0 },
});

console.log(response.output_text);

Note: it supports text/image input, instructions, function tools and streaming. Responses-only features (previous_response_id, built-in tools, background, …) throw a clear error. For full control, use tb.chat.completions.create.

Everything else from openai-node

TB.Client extends the OpenAI client, so per-request options work unchanged:

await tb.chat.completions.create(
  { model: "minimax/minimax-m2.7", messages: [{ role: "user", content: "hi" }] },
  {
    headers: { "x-my-header": "value" }, // custom headers
    timeout: 30_000,
    maxRetries: 1,
  },
);

Errors

Errors are the standard openai-node classes (APIError, RateLimitError, …). A 402 means no supplier fits your maxPrice, or your credits ran out — top up at https://tokenbanking.aimake.website/dashboard/credits.

Using the plain OpenAI SDK

Don't want to switch SDKs? The router is fully OpenAI-compatible — point the official openai client at TokenBanking and set the price-cap headers yourself:

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.TOKENBANKING_API_KEY,
  baseURL: "https://tb-proxy.aimake.website/v1",
});

const chat = await client.chat.completions.create(
  {
    model: "minimax/minimax-m2.7",
    messages: [{ role: "user", content: "Explain USDC in two sentences." }],
  },
  {
    headers: {
      // USD per 1M tokens; omit a header for no limit on that side
      "x-tb-max-price-input": "1.00",
      "x-tb-max-price-output": "1.00",
      // "x-tb-max-price-cached": "0.10",
    },
  },
);

Or set the caps once for every request via defaultHeaders:

const client = new OpenAI({
  apiKey: process.env.TOKENBANKING_API_KEY,
  baseURL: "https://tb-proxy.aimake.website/v1",
  defaultHeaders: {
    "x-tb-max-price-input": "1.00",
    "x-tb-max-price-output": "1.00",
  },
});

The same headers work with any HTTP client (curl, Python openai, etc.). If no supplier fits the caps, the router responds 402. Automatic fallback is a client-side feature of this SDK, so with plain openai you'd handle failover yourself.

Development

bun install
bun test          # run tests
bun run typecheck # tsc --noEmit
bun run build     # emit dist/