Meter LLM costs per tenant —
and enforce limits automatically

Usage metering and cost enforcement for LLM calls, built for multi-tenant B2B apps. One call instruments every OpenAI, Anthropic, Google AI, DeepSeek, and OpenRouter request — no changes to your LLM code.

Instrument once. Track and enforce everything.

TokenLimit patches provider SDKs at startup. Every call your application makes — including calls from libraries — is automatically captured, attributed, and checked against spend limits.

🔌

Patch at startup

Call meter.patch("provider_name") once when your app starts. All five provider SDKs are wrapped automatically — including calls made by libraries.

🏷️

Tag by tenant

Use meter.for_tenant() as a context manager. Thread-safe and async-safe via Python ContextVars. Works with sync and async code identically.

🚦

Enforce spend limits

Set a monthly or daily USD cap with meter.set_limit(). When a tenant hits the limit, LimitExceededException is raised — trigger your upgrade flow.

Background flush

Events queue in memory and batch POST to your ingest_url every 5 seconds. Your LLM calls are never blocked or slowed down.

📊

Full event schema

Every event carries provider, model, input/output/cached tokens, audio & image-specific fields, duration, request ID, and your custom tags.

Just a few lines to full coverage

Initialize at startup, call meter.patch("provider_name"), set per-tenant limits with set_limit(), and wrap handlers with for_tenant(). Catch LimitExceededException to trigger your upgrade flow.

Works with sync and async code
stream=True handled transparently
Per-tenant monthly or daily USD spend limits
LimitExceededException for upgrade flows
Zero changes to existing LLM calls
from token_limit import Meter, MeterConfig from token_limit import LimitExceededException
# Initialize once at startup meter = Meter(MeterConfig( api_key="your-api-key", )) meter.patch("openai") # anthropic, google, deepseek, openrouter
# Set a monthly spend cap per tenant meter.set_limit("acme-corp", limit_usd=50.00, frequency="per_day")# or default is per month
# Tag + enforce per request with meter.for_tenant("acme-corp"): try: response = client.chat.completions.create(...) except LimitExceededException: show_upgrade_message()

Works with every major LLM API

OpenAI

patched

chat, responses, embeddings, audio STT/TTS, image gen — sync & async, streaming & non-streaming

Anthropic

patched

messages.create — sync & async, streaming & non-streaming, prompt cache (read + write) tracking

Google AI

patched

generate_content + generate_content_stream — sync & async via google.genai client

DeepSeek

patched

chat, FIM, and beta chat — sync & async, streaming; covers first-party SDK and openai client

OpenRouter

patched

Instance-level patch on registered clients — sync & async, streaming, real USD cost capture

Any provider

custom

BasePatch extension for any LLM API, or meter.track_manually() for one-off calls