# Manual setup — Python (/docs/get-started/manual-python)



Add TokenPolice to a Python app in three steps. You'll need your
[API key and the collector URL](/docs/get-started/api-key) first.

## 1. Install [#1-install]

```bash
pip install token-police
```

Python 3.10 or newer. Provider libraries (OpenAI, Anthropic, …) are auto-instrumented — no
extra install for the common ones. Framework extras are on the
[integrations](/docs/integrations/matrix) page.

## 2. Initialize [#2-initialize]

Call `tp.init()` &#x2A;*once at startup, before you import or construct your LLM client.** That
ordering lets TokenPolice wrap the client automatically.

```python
import os
import token_police as tp

tp.init(
    api_key=os.environ["TOKENPOLICE_API_KEY"],   # tp_sk_...
    base_url="https://collect.tokenpolice.ai",   # the collector — always set this
    firewall="dry_run",                          # watch first; flip to "enforce" later
)

# Only now import and construct your LLM client:
from openai import OpenAI
client = OpenAI()
```

That's the whole integration. Every call `client` makes is now checked before it runs and
logged after — you'll see it in the dashboard.

<Callout type="info">
  `firewall="dry_run"` is the default and the right place to start: TokenPolice runs the
  full check and records what it *would* do, but never blocks. Flip it to `"enforce"` once
  your dashboard rules look right. See [Dry-run vs enforce](/docs/concepts/dry-run-vs-enforce).
</Callout>

## 3. Attach identity (recommended) [#3-attach-identity-recommended]

To budget per user or per session, wrap your entrypoint with `@tp.workflow`. It tags every
call inside with one identity and threads them into a single trace:

```python
@tp.workflow(name="support_agent")
def run_agent(user_id: str, paid_plan: str, session_id: str, query: str):
    return client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": query}],
    )
```

By default `@tp.workflow` reads `user_id`, `paid_plan`, and `session_id` straight from the
wrapped function's arguments — so calling `run_agent(user_id="u_123", paid_plan="pro",
session_id="chat_42", query=...)` attaches them automatically. These identities are what
budgets and rules match on. More in [Identity](/docs/concepts/identity).

## 4. Run it [#4-run-it]

Run your app as usual and make an LLM call. Then open
[app.tokenpolice.ai](https://app.tokenpolice.ai) — the call shows up with its token counts
and cost. Only token metadata is sent; your prompts and completions never leave your process
([what's in that record](/docs/concepts/data-privacy)).

## Then finish the job [#then-finish-the-job]

The three steps above get you metering. A production integration also names its steps, wraps
its tool calls, flushes before a serverless function freezes, and handles a blocked call —
and then proves all of it works. The
[integration checklist](/docs/get-started/integration-checklist) walks through the rest in
order.

## Next steps [#next-steps]

<Cards>
  <Card title="init() parameters" href="/docs/sdk/init" description="Every option, defaults, and env vars." />

  <Card title="Dry-run vs enforce" href="/docs/concepts/dry-run-vs-enforce" description="Turn on blocking when you're ready." />

  <Card title="Nothing in the dashboard?" href="/docs/troubleshooting/nothing-in-dashboard" description="Common first-run fixes." />

  <Card title="Integration checklist" href="/docs/get-started/integration-checklist" description="The rest of the steps, and how to verify." />

  <Card title="Node instead?" href="/docs/get-started/manual-node" description="The same setup in Node / TypeScript." />

  <Card title="See it in a running app →" href="/docs/sample-apps/support-agent" description="A full support-desk chat wired exactly like this, in Python and Node." />
</Cards>
