# Downgrade the model when budget is tight (/docs/recipes/downgrade-model)



Instead of blocking a user when their budget runs out, keep them working on a cheaper model. A
**Reroute** rule swaps the model before the call is dispatched, so your app never sees the
difference.

## The rule [#the-rule]

On the Firewall page, **Cost & access** tab, click **New rule from template** and pick a
**Save money** card:

<Steps>
  <Step>
    **Switch to a cheaper model after $X** — the budget-gated version. Set the amount you want to
    switch after, the reset period, and the cheaper model. Until the pool crosses that limit, calls
    run normally.
  </Step>

  <Step>
    **Send free users to a cheaper model** — the unconditional version. No limit at all: *every* call
    on the plan you name is swapped, from the first one. There are per-team and per-session variants
    too (*Switch each team or feature to a cheaper model after $X*, *Switch a session to a cheaper
    model after $X*).
  </Step>
</Steps>

<Callout type="warn">
  **Same-provider swaps only** — pick a smaller or cheaper model from the same provider. A
  cross-provider target is rejected. The target also has to be a model TokenPolice already has
  pricing for, or the rule won't save.
</Callout>

<Callout type="warn" title="Check the swap really happens in your app">
  Reroute does not switch the model on some frameworks — including LangChain, LangGraph,
  LlamaIndex, Pydantic AI, and the Vercel AI SDK. Those calls still run on the original model.
  Confirm a swap actually happens in your app before you enforce this in production.
</Callout>

## The snippet [#the-snippet]

There's **nothing to change in your request code** — the SDK rewrites the model and your
`create()` call returns from the cheaper model as normal. The only requirement is that your app
runs in enforce, since reroute (like block) only acts when both dials say enforce:

```python
import token_police as tp

tp.init(
    api_key=os.environ["TOKENPOLICE_API_KEY"],
    base_url="https://collect.tokenpolice.ai",
    firewall="enforce",          # in dry_run the reroute is only recorded, not applied
)
```

```typescript
import { init } from "token-police";

init({
  apiKey: process.env.TOKENPOLICE_API_KEY!,
  baseUrl: "https://collect.tokenpolice.ai",
  firewall: "enforce",
});
```

A reroute never silently unpins a model you asked for: if the target resolves to the same model
you already requested, nothing is swapped.

In Dry-run the rule records a &#x2A;"Would reroute…"* projection instead of acting, so you can see how
often it would fire before you turn it on — check it in the [dashboard](/docs/dashboard). See
[Actions](/docs/rules/actions#reroute).

## Next [#next]

<Cards>
  <Card title="Actions" href="/docs/rules/actions" description="Block, notify, and reroute in detail." />

  <Card title="Cap free-tier users" href="/docs/recipes/cap-free-tier" description="Block instead of reroute when the budget's gone." />

  <Card title="Cheaper-model routing" href="/solutions#routing" description="Where rerouting fits, and what it does not claim to save." />
</Cards>
