fewertokens
Python SDK for FewerTokens — a control-plane client for cross-family LLM routing.
The SDK asks FewerTokens which provider/model to use, then calls that model locally via LiteLLM with your provider keys. Usage is reported back asynchronously.
Install
pip install fewertokens
Quick start
from fewertokens import FewerTokens
ft = FewerTokens(
api_key="tr_live_...", # your FewerTokens key from the dashboard
openai_api_key="sk-proj-...",
openai_default_model="gpt-4o", # your current default — savings are measured against this
anthropic_api_key="sk-ant-...",
anthropic_default_model="claude-sonnet-4-6", # priced default so routing can save money
gemini_api_key="AIzaSy...",
gemini_default_model="gemini-3.1-pro-preview", # priced default so routing can save money
base_url="https://api.fewertokens.in",
)
response = ft.chat.completions.create(
messages=[{"role": "user", "content": "What is Python?"}],
)
# The answer
print(response.content)
# Which model was actually used (may be cheaper than your default)
print(f"Routed to: {response.routing.provider}/{response.routing.model_used}")
print(f"Baseline was: {response.routing.baseline_model}")
# Token usage
print(f"Tokens — prompt: {response.usage.prompt_tokens}, completion: {response.usage.completion_tokens}")
# Estimated savings for this request (USD)
print(f"Estimated saving this call: ${response.routing.estimated_savings_usd:.6f}")
Response object
ft.chat.completions.create(...) returns a ChatResponse — not the OpenAI SDK object. Key attributes:
| Attribute | Type | Description |
|---|---|---|
response.content |
str |
The model's reply text |
response.model |
str |
Exact model string returned by the provider |
response.finish_reason |
str | None |
e.g. "stop" |
response.usage.prompt_tokens |
int |
Input tokens billed by the provider |
response.usage.completion_tokens |
int |
Output tokens billed by the provider |
response.routing.provider |
str |
Provider family used (e.g. "gemini") |
response.routing.model_used |
str |
Model dispatched (e.g. "gemini-3.1-flash-lite") |
response.routing.baseline_model |
str | None |
Your configured default (the savings baseline) |
response.routing.estimated_savings_usd |
float |
Estimated USD saved vs your baseline for this call, from the published catalog's USD input rates (0 for unlisted or unpriced models and fallbacks) |
response.routing.fallback_reason |
str | None |
None, "route_unavailable" or "routed_model_error" (see "How it works") |
response.raw |
dict |
Full raw provider response |
How it works
- Route handshake —
POST /v1/routewith the routing prompt (yoursystemmessages + the lastusermessage only; the rest of the conversation is never sent, see "What FewerTokens receives" below) +provider_models(each provider key's default model). The whole handshake (DNS, connect, send, receive) has one 800 ms deadline. - Local dispatch —
litellm.completion/acompletionwith the routed provider key - Telemetry — background
POST /v1/telemetrywithroute_id+ token usage. The completion call does not wait, and a failed report does not raise.close(), the context manager (withandasync with), and process exit wait up to 2 seconds for a report still in flight. That wait does not raise.
If the control plane is unreachable, slow, or rejects the request (including an invalid FewerTokens API key), the SDK calls your first configured *_default_model locally and skips telemetry, so there is no fee. FewerTokens must not be the reason a prompt never reaches the LLM provider. response.routing.fallback_reason is "route_unavailable" in that case.
When an invoice hasn't been paid, the response comes back as HTTP 402 with error code routing_paused. The SDK logs one warning per client on the fewertokens.chat logger: "FewerTokens routing is paused because an invoice hasn't been paid. Pay it using the link in your invoice email to turn routing back on." That call goes to your default model and sends no usage telemetry, so no fee is charged.
If the routed model fails on the provider side (5xx, overloaded, 429 rate limit, timeout, connection error), the SDK retries once on your first configured *_default_model. Telemetry marks the call as a fallback, so no fee is charged, and response.routing.fallback_reason is "routed_model_error". Errors caused by the request or your account (400/422, 401/403, 404, content policy, context length) are raised without a retry. For streams, the retry only happens if the routed stream fails before its first chunk; once tokens have reached your code, a mid-stream error is raised.
Privacy & Security
🔒 Privacy & Security First:
- Zero Key Exposure: Your provider keys stay strictly in your client runtime's RAM memory and are never sent to FewerTokens servers.
- Direct Local Execution: Prompt content and response streams flow directly between your machine and LLM provider endpoints (OpenAI, Anthropic, Gemini, etc.). FewerTokens only receives the routing prompt (your
systemmessages + the lastusermessage, see "What FewerTokens receives" below) for the routing decision (~20ms) and never sees or logs completion payloads.
Streaming
for chunk in ft.chat.completions.create(
messages=[{"role": "user", "content": "Explain Docker"}],
stream=True,
):
print(chunk.content, end="", flush=True)
Async
response = await ft.chat.completions.acreate(
messages=[{"role": "user", "content": "Hello!"}],
)
Notes
- At least one of
openai_api_key,anthropic_api_key, orgemini_api_keyis required, and each key must have a matching*_default_model. - String shorthand:
prompt="Hello"is accepted as an alternative tomessages=. model=on.create()is ignored — the control plane decides the model.- Your
*_default_modelis the savings baseline: set it to the model you are currently calling. If you set it to an already-cheap model, there is nothing to save and the fee is$0. - FewerTokens never sees your provider API keys or completion payloads. Keys stay in your process RAM.
What FewerTokens receives
Since 0.3.0, POST /v1/route carries exactly three fields: prompt, available_providers and provider_models.
promptis built locally from your messages:- all of your
systemmessages, joined; - plus the last
usermessage only; - only text parts are used; images and other non-text parts are dropped;
- if there is no
usermessage at all, the last message of any role is used instead.
- all of your
- Earlier user turns, assistant replies and tool results are never sent. The full conversation goes only to your LLM provider, through LiteLLM on your machine. (0.2.x sent the whole
messageslist as well.) - The server's classifier reads at most the first 256 tokens of
prompt. - The SDK sends at most the first 8,192 characters of
prompt. Apromptlonger than 32,000 characters is rejected by the API. The SDK then calls your default model directly: there is no routing and no fee. available_providersandprovider_modelscarry your provider names and each provider's*_default_modelid.POST /v1/telemetrycarries theroute_idand token counts. For a retried call it also carriesfallback,fallback_providerandfallback_model. It never carries prompt or completion text.
Default model has no verified price
You may see this warning once per process, on the fewertokens.pricing logger:
Your default model has no verified price, so routing and fees are off. Pick a priced default to turn them on. See https://pypi.org/project/fewertokens/#user-content-default-model-has-no-verified-price
What it means. Your default model is the *_default_model of the first provider you configure (OpenAI, then Anthropic, then Gemini, then extra_providers in order). FewerTokens has no verified price for it, so it can't measure savings against it. Your calls still work: every call goes straight to your default model, with no routing and no fee. The SDK never switches your default model for you.
The SDK logs the warning when you create the client and your default model isn't in its price table, or when POST /v1/route reports routing_disabled_reason: "default_model_unpriced".
How to fix it. Your default model is set in your SDK config, not on the dashboard. Pass a priced model as the *_default_model of your first provider:
from fewertokens import FewerTokens
ft = FewerTokens(
api_key="tr_live_...",
anthropic_api_key="sk-ant-...",
anthropic_default_model="claude-sonnet-4-6", # was "claude-3-5-sonnet", which has no verified price
)
For providers in extra_providers, set "default_model" in that provider's entry.
How to check whether a model is priced. The SDK's price table holds the models in the published FewerTokens catalog (1.2.1). Priced defaults include gpt-4o, gpt-4.1 and gpt-5.5 (OpenAI), claude-sonnet-4-6 and claude-opus-4-7 (Anthropic), and gemini-3.1-pro-preview (Gemini). Models the catalog dropped, such as claude-3-5-sonnet, o1-mini, gpt-5.6, gemini-2.0-flash, grok-4, and (in 1.2.1) gemini-2.5-pro, gemini-2.5-flash, o1 and o4-mini, have no verified price, and neither do fine-tunes or other models outside the catalog.
To check your own config, create the client with logging on. If the warning doesn't appear when you create the client or on your first call, your default model is priced:
import logging
logging.basicConfig(level=logging.WARNING)
ft = FewerTokens(api_key="tr_live_...", openai_api_key="sk-proj-...", openai_default_model="gpt-4o")
How to silence it or route it. The SDK adds no log handlers. The warning goes through Python's standard logging, so your logging config decides where it ends up. Without any config, Python prints it to stderr.
import logging
# Silence it:
logging.getLogger("fewertokens.pricing").setLevel(logging.ERROR)
# Or send it to your own handler instead of the root logger:
pricing_log = logging.getLogger("fewertokens.pricing")
pricing_log.addHandler(logging.FileHandler("fewertokens.log"))
pricing_log.propagate = False
Silencing the warning doesn't turn routing back on. Only a priced default model does that.
Metadata
Release files for fewertokens 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fewertokens-0.3.2.tar.gz | 36.9 kB | With provenance | Details for fewertokens-0.3.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fewertokens-0.3.2-py3-none-any.whl | Python 3 | none | any | Details for fewertokens-0.3.2-py3-none-any.whl |
Total release size: 71.1 kB
Release files / fewertokens-0.3.2.tar.gz
| Download URL | fewertokens-0.3.2.tar.gz |
|---|---|
| Size | 36.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0393f141e8847a7c7cb87c7c280bf56787de109a0a5d8c0bf189920c38abfc2f
|
|
BLAKE2b-256 checksum How to use checksums |
d2b4f2ca16baa0c1a03ddfdbc155d9d8dffa770c610acb3797b4aa50094316ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / fewertokens-0.3.2-py3-none-any.whl
| Download URL | fewertokens-0.3.2-py3-none-any.whl |
|---|---|
| Size | 34.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
08823a9392584fd2dea01b358d964f6ece218bb864d9a589984769124fdbec56
|
|
BLAKE2b-256 checksum How to use checksums |
32cf2edc8e8ded7c2f6f8ac3462ae61175facec11d564686525d197f9f72ae90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logSecurity for fewertokens 0.3.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for fewertokens-0.3.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.