Metadata-Version: 2.4
Name: tokeven
Version: 0.9.2
Summary: Privacy first cost visibility for Claude, ChatGPT, Gemini, and Grok (xAI) API calls. Metrics only: your provider keys and prompt content never reach Tokeven.
Author-email: Tokeven <team@tokeven.com>
Maintainer-email: Tokeven <team@tokeven.com>
License-Expression: LicenseRef-Tokeven-Proprietary
Project-URL: Homepage, https://tokeven.com
Project-URL: Documentation, https://tokeven.com/docs
Project-URL: Pricing, https://tokeven.com/pricing
Project-URL: Privacy, https://tokeven.com/privacy
Project-URL: Security, https://tokeven.com/security
Project-URL: Changelog, https://tokeven.com/docs#changelog
Keywords: anthropic,claude,openai,gemini,xai,grok,llm,cost,observability,tokens,finops,mcp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40; extra == "anthropic"
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == "openai"
Provides-Extra: xai
Requires-Dist: openai>=1.0; extra == "xai"
Requires-Dist: xai-sdk>=1.20; extra == "xai"
Provides-Extra: google-genai
Requires-Dist: google-genai>=1.0; extra == "google-genai"
Provides-Extra: requests
Requires-Dist: requests>=2.28; extra == "requests"
Provides-Extra: mcp
Requires-Dist: mcp<3.0,>=2.0; extra == "mcp"
Provides-Extra: proxy
Requires-Dist: starlette>=0.37; extra == "proxy"
Requires-Dist: uvicorn>=0.29; extra == "proxy"
Requires-Dist: pydantic-settings>=2.2; extra == "proxy"
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2; extra == "langchain"
Provides-Extra: litellm
Requires-Dist: litellm>=1.40; extra == "litellm"
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.1; extra == "openai-agents"
Provides-Extra: menubar
Requires-Dist: rumps>=0.4; sys_platform == "darwin" and extra == "menubar"
Provides-Extra: all
Requires-Dist: anthropic>=0.40; extra == "all"
Requires-Dist: openai>=1.0; extra == "all"
Requires-Dist: google-genai>=1.0; extra == "all"
Requires-Dist: xai-sdk>=1.20; extra == "all"
Requires-Dist: mcp<3.0,>=2.0; extra == "all"
Requires-Dist: starlette>=0.37; extra == "all"
Requires-Dist: uvicorn>=0.29; extra == "all"
Requires-Dist: pydantic-settings>=2.2; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: httpx>=0.24; extra == "dev"
Requires-Dist: anthropic>=0.40; extra == "dev"
Requires-Dist: openai>=1.0; extra == "dev"
Requires-Dist: google-genai>=1.0; extra == "dev"
Requires-Dist: mcp<3.0,>=2.0; extra == "dev"
Requires-Dist: starlette>=0.37; extra == "dev"
Requires-Dist: uvicorn>=0.29; extra == "dev"
Requires-Dist: pydantic-settings>=2.2; extra == "dev"
Provides-Extra: integrations-test
Requires-Dist: langchain-core>=0.2; extra == "integrations-test"
Requires-Dist: langchain-openai>=0.3; extra == "integrations-test"
Requires-Dist: langchain-anthropic>=0.3; extra == "integrations-test"
Requires-Dist: litellm>=1.40; extra == "integrations-test"
Requires-Dist: openai-agents>=0.1; extra == "integrations-test"
Requires-Dist: xai-sdk>=1.20; extra == "integrations-test"
Dynamic: license-file

# tokeven

<!-- mcp-name: com.tokeven/tokeven -->

Per prompt cost visibility for the Claude, OpenAI, and Google SDKs, without
Tokeven ever holding a provider key or seeing a prompt.

`tokeven` wraps the official provider SDKs. Your call goes to the provider
exactly as before, and the wrapper reads the `usage` block off the response and
pushes a small metrics event to your Tokeven dashboard. It also answers the
question that saves the most money, which is what a call is about to cost before
you send it.

- Website: https://tokeven.com
- Documentation: https://tokeven.com/docs
- Pricing: https://tokeven.com/pricing
- Free teardown tool, no account needed: https://tokeven.com/teardown

## Thirty seconds, no install, no account

```bash
uvx tokeven teardown
```

Reads the Claude Code session logs already on your machine, prices them against
live rates, and prints what you have actually been spending. It makes zero
network calls and asks for nothing. Paste the output at
https://tokeven.com/teardown for the breakdown by model, or keep it local.

## What it does

- Estimates cost and confidence across all three providers before you send a
  call, so model choice is an informed decision rather than a default.
- Records what each call actually cost, with cache aware pricing recomputed
  server side.
- Runs as an MCP server, so Claude Code can ask for an estimate directly.
- Ships a live cost widget for your shell prompt or status line, and a self
  hosted sidecar for capturing usage without an SDK wrapper.
- Suggests cheaper models and prompt level efficiency improvements, and always
  leaves the decision to you. Nothing is rerouted silently.

## Privacy

- Tokeven receives token counts and metadata such as model, latency, and a
  character count computed locally. Prompt and completion content never reaches
  Tokeven through this pipeline.
- Every outgoing event passes a strict key allowlist, so content cannot be
  transmitted by accident.
- Authentication to Tokeven uses a write only ingest token, which cannot read
  your data or manage your account. It is not a provider key, and Tokeven never
  asks for one.
- `tokeven reconcile` reads your provider's billing report with a provider ADMIN
  key. That key is read from this machine's environment, used here, and never
  transmitted. Tokeven has no endpoint that accepts it. Only daily totals are
  sent.
- `TOKEVEN_ACTOR` is opt in and off by default. If you set it, the label you
  choose is attached to your events so your team can see who drives spend. It is
  a label you pick, not something derived from your prompts.
- Two features are opt in exceptions that do send prompt text you explicitly hand
  them, because rewriting a prompt requires reading it: the prompt revision tool
  on the website and `advisor.improve()`. Both are disclosed at the point of use.
  Details at https://tokeven.com/privacy
- Tool names are sent as-is by default. Set `TOKEVEN_HASH_TOOL_NAMES=1` (or
  `hash_tool_names=True`) to send a short hash keyed by your ingest token instead,
  so tool trends still work but your function names never leave the machine.
  Because the key is the token, rotating it, or using several tokens in one
  organization, makes the same tool hash differently from then on.
- Fine-tuned model ids are reduced to their base model (`ft:gpt-4o-mini`) before
  they are sent, so the organization and suffix segments stay local.
- If any part of the instrumentation fails, your provider call is returned
  unchanged. Tokeven is designed not to break your application.

## Install

```bash
pip install tokeven                  # wrapper, advisor, CLI, widget
pip install "tokeven[anthropic]"     # with the Anthropic SDK
pip install "tokeven[openai]"        # with the OpenAI SDK
pip install "tokeven[google-genai]"  # with the Google SDK
pip install "tokeven[xai]"           # for xAI / Grok (OpenAI SDK + native xai-sdk)
pip install "tokeven[mcp]"           # with the MCP server
pip install "tokeven[proxy]"         # with the self hosted sidecar
pip install "tokeven[all]"           # everything
```

Requires Python 3.11 or newer. On 3.10 and older pip reports no matching
distribution rather than a version error.

For the command line tools on their own, without touching a project environment:

```bash
pipx install tokeven
```

## Quickstart

Wrap your existing provider client. Configuration is read from the environment:
`TOKEVEN_INGEST_TOKEN`, `TOKEVEN_BASE_URL`, `TOKEVEN_PROJECT`, `TOKEVEN_MODE`,
`TOKEVEN_ACTOR`.

```python
from anthropic import Anthropic
from tokeven import TokevenAnthropic

client = TokevenAnthropic(Anthropic(), project="billing-agent")

resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.content)   # unchanged Anthropic response

client.flush()   # optional: push now instead of on the next background tick
```

Recording an event never touches the disk or the network on your call's thread
(or event loop): it is an in-memory append, and a background thread pushes
batches. If Tokeven is unreachable, nothing blocks your process: events wait in
a local durable queue and are sent on the next run. `flush()` and `close()` are
bounded (default 5s, `TOKEVEN_FLUSH_TIMEOUT_S`), and pending events get a short,
bounded push when the interpreter exits (default 2s,
`TOKEVEN_SHUTDOWN_TIMEOUT_S`).

### Durability

- **What survives:** normal exit, `close()`, exceptions, Ctrl-C, SIGTERM handled
  by your framework, Tokeven outages, and restarts. Undelivered events stay on
  disk and are sent later.
- **The one window:** events are moved from memory to disk every
  `flush_interval_s` (config kwarg, default 5s), or sooner once `flush_threshold`
  (default 50) are pending. Sending runs on its own thread, so a slow or hung
  request to Tokeven never delays this. A hard kill (`SIGKILL`, `os._exit`, OOM,
  power loss) can lose the events from at most that last interval. Call
  `flush()` after a critical call if you need it on disk immediately.
- **Many processes:** gunicorn/uvicorn workers, Celery prefork and
  `multiprocessing` children each write their own queue segment, so they never
  overwrite each other, and a backlog is sent exactly once by whichever process
  claims it. Segments left by a crashed process are picked up by the next live
  one. Forked children are safe: they get fresh locks and their own sender.
- **Bounded:** the queue holds at most `queue_max_events` (default 10,000;
  `TOKEVEN_QUEUE_MAX_EVENTS` for the sidecar); beyond that the oldest events are
  dropped, with one warning. After the free tier's monthly cap is reached,
  sending pauses but events keep being stored (within that bound); one batch is
  retried every hour, so an upgrade resumes delivery without a restart, and the
  pause ends at the start of the next month.

`TokevenOpenAI` and `TokevenGemini` wrap the OpenAI and Google SDKs the same way.
Async clients work too: `wrap(AsyncAnthropic())`, `wrap(AsyncOpenAI())`, and
`client.aio` on a wrapped `genai.Client`, including streaming.

For xAI / Grok, use `TokevenXAI`. Grok is served over the OpenAI SDK against
`api.x.ai`, so there is no separate xAI package to install:

```python
from tokeven import TokevenXAI

client = TokevenXAI(project="research-agent")   # reads XAI_API_KEY

resp = client.chat.completions.create(
    model="grok-4.6",
    messages=[{"role": "user", "content": "Hello"}],
)
```

`wrap()` recognises Grok too, including a client you built yourself:

```python
from openai import OpenAI
from tokeven import wrap

client = wrap(OpenAI(base_url="https://api.x.ai/v1", api_key="..."))
```

xAI's native gRPC SDK (`xai_sdk`) is wrapped too. `sample()`, `stream()`,
`parse()` and `defer()` on chats created through the wrapper are tracked; the
xAI Batch API, `image` and `video` are not yet, and reaching them logs a
one-time warning:

```python
import xai_sdk
from xai_sdk.chat import user
from tokeven import wrap

client = wrap(xai_sdk.Client())
chat = client.chat.create(model="grok-4.6")
chat.append(user("Hello"))
response = chat.sample()
```

Two Grok pricing quirks worth knowing, both handled for you: cached input is
priced per model rather than as one family-wide discount, and every Grok model
charges double — input *and* output — once a prompt reaches 200,000 tokens.

### Instrument every client automatically

Instead of wrapping each client, call `tokeven.instrument()` once at startup.
Every Anthropic, OpenAI (including Azure and Grok-over-OpenAI), Google GenAI and
`xai_sdk` client created afterwards is tracked, Bedrock, Vertex and Foundry
variants included:

```python
import tokeven
tokeven.instrument(project="billing-agent")   # same options as wrap()

from anthropic import Anthropic
client = Anthropic()          # still an anthropic.Anthropic, now tracked
```

- It is opt in and idempotent. `tokeven.uninstrument()` restores the original
  constructors; clients already created stay tracked. Calling `instrument()`
  again with different options logs a warning; clients created after that use
  the new options, and clients created before keep theirs.
- Clients stay instances of the SDK's own class, so type checks and
  `with_options()` keep working.
- SDKs that are not imported yet are patched when your code imports them, so
  `instrument()` adds no import time of its own.
- Calling `wrap()` on an instrumented client is safe. Each call is still recorded
  once.
- Combining it with a framework integration (LangChain, LiteLLM, the Agents SDK)
  is safe too: a call the instrumented SDK client already recorded is not
  reported again by the integration, and a call the framework makes over its own
  HTTP client (LiteLLM's Anthropic route, for example) is still reported by the
  integration. This relies on the call running in the context the framework's
  start hook ran in; work you move to a thread pool yourself without copying the
  context can still be counted twice.
- If instrumenting a client fails, the client is returned exactly as the SDK
  built it.

Without touching the code at all:

```bash
python -m tokeven.run app.py --your --args       # or: python -m tokeven.run -m package.module
TOKEVEN_AUTO_INSTRUMENT=1 python app.py          # when app.py imports tokeven
```

No `sitecustomize` or `.pth` file is installed, so nothing outside these two
entry points is ever patched.

### Which calls are tracked

Beyond `create`, the wrappers cover:

- Anthropic: `messages.parse`, `messages.stream`, `with_raw_response`,
  `with_options()`, everything under `beta.messages` including `tool_runner`
  (each turn of the loop is one event), and Message Batches results.
- OpenAI and Grok: `chat.completions.parse` and `.stream()`,
  `responses.parse` and `.stream()`, `with_raw_response`, `with_options()`, and
  Batch API output files read with `files.content()`.
- Google: `client.chats` (sync and `aio`), Google Search grounding queries (as
  web-search calls), tool-use prompt tokens, and batch jobs read with
  `batches.get()` or a results file read with `files.download()`.

Batch results produce one event per succeeded request, flagged as batch so it is
priced at the batch rate. Each event's id is derived from the batch and request
ids, so reading the same results twice is counted once. Audio tokens (OpenAI
audio models, Gemini audio input and output) are reported as their own share of
each total, and calls through Bedrock, Vertex and Azure carry the platform and a
normalized model id. Anything billable that is still passed through unwrapped,
such as `embeddings`, logs a one-time warning that it is not tracked.

## First run

The fastest path is one command:

```bash
tokeven init
```

It prints a short code and opens your browser. Approve it while signed in to
Tokeven, and the command:

- receives a new write only ingest token (never a login session, and no
  provider key is read or sent),
- writes `TOKEVEN_INGEST_TOKEN` to `.env` (created with mode 600 if missing,
  updated in place otherwise; `--env-file PATH` to choose another file). The
  full token is never printed,
- sends one test event, which the server acknowledges but never counts as
  usage, spend or toward the free tier cap,
- prints your dashboard link and the next step (`wrap()` or the sidecar).

`--base-url URL` points it at another Tokeven API, and `--no-browser` only
prints the link (for SSH sessions). `tokeven ping` re-sends the test event any
time to check a token and the network path.

To set the token by hand instead:

```bash
export TOKEVEN_INGEST_TOKEN="tkv_ing_..."
export TOKEVEN_BASE_URL="https://api.tokeven.com"
```

Create a token at https://tokeven.com/settings/tokens

Estimate the cost of a call before you send it:

```bash
tokeven estimate --model claude-opus-4-8 "your prompt here"
```

The estimate runs entirely on your machine and needs no account at all.

## Use it from Claude Code (MCP)

The advisor runs as an MCP server, so Claude can price a call before it makes
one. It is listed in the MCP registry as `com.tokeven/tokeven`, or add it by
hand:

```bash
claude mcp add tokeven -- uvx --with 'mcp>=2.0,<3.0' tokeven mcp
```

`tokeven mcp` and `tokeven-mcp` are the same server; the subcommand form is what
registry installs launch.

The MCP server estimates and advises. It does not track: nothing it does emits a
usage event, because `wrap()` and the sidecar are the only capture paths.
`tokeven status` reports which of those are actually live on this machine.

## Is it actually tracking? (`tokeven status`)

Instrumentation that is configured but inert looks exactly like instrumentation
that works, so there is one command that says which it is:

```bash
tokeven status
```

It reports which capture paths are live (and that the MCP server is an estimator,
not a tracker), the resolved `base_url` and where that value came from, the ingest
token prefix and its source, whether `base_url` is reachable, how many events are
sitting undelivered in the local durable queue, and a plain verdict on whether
anything is being tracked right now. It needs no login, works offline
(`--offline` skips the reachability probes), never prints your full token, and
exits non zero when it finds problems so you can use it in a script. `--json`
gives the same report machine readably.

## Frameworks, OpenTelemetry and budget guard (optional)

Every integration is metrics only (token counts, model, provider), imports its
framework lazily, and fails open. Events go to the same `/ingest` as `wrap()`.

```python
# LangChain: pip install "tokeven[langchain]"
from tokeven.integrations.langchain import TokevenCallbackHandler
llm = ChatAnthropic(model="claude-sonnet-4-6", callbacks=[TokevenCallbackHandler()])

# LiteLLM: pip install "tokeven[litellm]"  (one TokevenLogger per process; LiteLLM de-dupes by class)
# Responses served from LiteLLM's own cache are not counted: no provider call was made.
import litellm
from tokeven.integrations.litellm import TokevenLogger
litellm.callbacks = [TokevenLogger()]

# OpenAI Agents SDK: pip install "tokeven[openai-agents]"
from agents import add_trace_processor
from tokeven.integrations.openai_agents import TokevenTracingProcessor
add_trace_processor(TokevenTracingProcessor())
# Works with trace_include_sensitive_data=False: only usage and the model name are read.
```

**Generic OpenTelemetry GenAI.** `tokeven capture` also accepts OTLP/JSON spans
(`/v1/traces`) and log records that follow the GenAI semantic conventions
(`gen_ai.system`, `gen_ai.request.model` / `gen_ai.response.model`,
`gen_ai.usage.input_tokens` / `output_tokens`, cache read/creation). Opt in with
`TOKEVEN_GENAI_CAPTURE=1`; it is independent of `TOKEVEN_FLAT_RATE_CAPTURE`, and
these events are priced normally. Only leaf inference spans count (agent and
tool spans are skipped so nothing is double-billed); prompt and completion
attributes are never read. Semconv defines `input_tokens` as including cached
tokens; set `TOKEVEN_GENAI_INPUT_EXCLUDES_CACHE=1` if your instrumentation
reports it excluding them. Run `tokeven capture --setup` for the exporter env.

**Budget guard.** A local, in-process spend limit that stops the next call and
never reroutes or switches models:

```python
from tokeven import guard

with guard.budget(max_usd=2.00, per="session", action="raise"):
    run_agent()                   # TokevenBudgetExceeded before the next call

@guard.budget(max_usd=5, per="process", action="warn")
def nightly(): ...
```

Spend is a local list-price estimate fed by every event captured in your
process (`wrap()`, `instrument()`, the framework integrations), so it needs no
network and no ingest token. Calls sent through the sidecar are captured in the
sidecar's process and do not count toward a guard in your app. An event read
twice (e.g. iterating the same batch results again) is counted once.

A `with`/decorator guard is scoped to the thread or asyncio task that entered
it (and tasks it creates), so concurrent requests each see only their own
spend. `per="process"` counts all of the process's spend but is still enforced
only where it was entered; `guard.budget(...).install()` applies one guard to
every thread. Work handed to a plain thread pool inside a block does not
inherit it. The check runs where code calls `guard.check()`:
automatically in the LangChain handler (`on_llm_start`), LiteLLM's async calls
(`litellm.acompletion`, the Router and the proxy), and the Agents SDK via
`guard_run_hooks()`. A bare `wrap()` client or a sync `litellm.completion()` call
is not intercepted; call `guard.check()` before it.

Each emitted call is also appended to a small local ledger (token counts, model
and cost, no content; 3-day retention; `TOKEVEN_LOCAL_LEDGER=0` disables the
file). The MCP server's `session_cost` tool reads it to report estimated spend
for a session or time window.

## The sidecar (optional)

If you would rather not wrap an SDK, run the self hosted sidecar and point your
provider base URL at it. It forwards every request to the provider verbatim and
captures usage on a fail open side channel. Provider keys and prompt content
never reach Tokeven.

```bash
pip install "tokeven[proxy]"
tokeven-proxy
```

Point each SDK at the proxy in place of its provider:

| Provider | Base URL |
|---|---|
| Anthropic | `http://localhost:7779` |
| OpenAI | `http://localhost:7779/v1` |
| Google | `http://localhost:7779` |
| xAI / Grok | `http://localhost:7779/xai/v1` |

Grok is namespaced because xAI serves OpenAI's exact paths, so the proxy has no
other way to tell the two apart. It costs nothing: reaching `api.x.ai` already
requires a custom base URL. The `/xai` segment is stripped before forwarding, so
xAI sees the request your SDK built.

The sidecar also captures batch traffic: Anthropic Message Batches results (the
proxy points each batch's `results_url` back at itself, so the SDK's results
download passes through it), and OpenAI Batch API output files downloaded
through `/v1/files/{id}/content`
(`/v1/batches` itself is forwarded but never counted, since the per-request
results already are). `TOKEVEN_HASH_TOOL_NAMES=1` works here as well.

A container image and an example `docker-compose.yml` ship alongside this package.

## The live cost widget (optional)

A one line spend gauge for your shell prompt, tmux, or editor status line. It
reuses your dashboard login, never an ingest token or a provider key.

```bash
tokeven-widget            # print one status line and exit
tokeven-widget watch      # poll and reprint on an interval
```

On macOS there is also an always-visible menubar version: month-to-date spend
across every provider, amber at 80% of your monthly budget and red at 100%.

```bash
pip install "tokeven[menubar]"
tokeven-menubar
```

Both read the same settings: `TOKEVEN_API_TOKEN`, or `TOKEVEN_EMAIL` +
`TOKEVEN_PASSWORD`.

## What is and is not tracked

Tokeven sees the traffic you instrument. Calls made through the provider
consoles, through the Anthropic Workbench, or from applications you have not
wrapped will not appear on the dashboard.

`tokeven reconcile` tells you how big that gap actually is. It reads your
provider's own daily cost report and pushes the totals, so the dashboard can show
what fraction of your real bill Tokeven can see instead of just warning you that
some of it is missing.

```bash
export ANTHROPIC_ADMIN_KEY=...      # or OPENAI_ADMIN_KEY; stays on this machine
tokeven reconcile --days 30         # add --dry-run to look before sending
```

Anthropic and OpenAI expose a billing API to an organization admin key. Google's
cost data lives in Cloud Billing exports and xAI has no equivalent endpoint, so
for those, export a CSV from the provider console:

```bash
tokeven reconcile --csv billing.csv --provider google
```

## Who is spending it

By default the only link from a call to a person is the ingest token that pushed
it, so a team sharing one token — or a CI pipeline — shows up as a single
anonymous bucket. Set `TOKEVEN_ACTOR` to label calls:

```bash
export TOKEVEN_ACTOR="zoe@example.com"   # or "zoe", or "build-agent-7"
```

If the label matches a team member's email, the dashboard attributes the spend to
them; if it matches nobody, it is reported under the label itself rather than
guessed at. Opt in, and unset by default.

## Free and paid

Everything this package does on your machine is free, and there is no trial clock
on it. That includes pre send cost estimates, the model picker, efficiency
suggestions, the MCP server, the sidecar, and the live cost widget. A free
Tokeven account adds a dashboard covering 1,000 tracked calls per month.

The paid tier is priced as gainshare. Tokeven earns 10 percent of verified
savings, measured per call against live token prices rather than a frozen
baseline, and you keep the other 90 percent. If you save nothing, you pay
nothing, and the fee falls automatically when model prices fall. There is no per
seat charge.

Paid adds:

- Unlimited tracked calls
- Prompt revision suggestions
- Organization wide savings dashboard and per person savings tracking
- Analytics across all three providers
- Embeddable widgets
- n8n and webhook integrations
- CSV, JSON, and API export

Enterprise terms, including capped arrangements for teams that budget fixed line
items, SSO, and custom retention, are handled case by case.

If you are weighing the paid tier or want a hand sizing what you would actually
save, email team@tokeven.com. We are happy to look at your numbers with you, and
there is no obligation attached to asking. Full pricing detail is at
https://tokeven.com/pricing

## License

Proprietary. The full terms ship in the `LICENSE` file bundled with this
package. Questions: team@tokeven.com
