# Override a price

Correct or supply a rate without rebuilding the binary. Overrides take effect on a date, retire rather than disappear, and stamp every row they price.

Source: https://tokentriage.com/docs/build/dashboard-pricing-overrides

---
import Callout from '../../../components/Callout.astro';
import Details from '../../../components/Details.astro';
import NextSteps from '../../../components/NextSteps.astro';
import Screenshot from '../../../components/Screenshot.astro';

The Pricing surface is showing rows as `UNPRICED`, or the embedded table has a rate that does
not match the contract you signed. You need a different price without waiting for the next
release.

An override supplies one. What makes it worth a page is not the substitution but the three
rules around it: an override applies from a date, it retires rather than disappears, and it
brands every row it prices so an overridden dollar can never be mistaken for a catalogue one.

## Point the config at an artifact

```yaml
pricing:
  overrides_file: /var/lib/tokentriage/pricing-overrides.json
```

One file, layered over the embedded price table. It is read at boot, so changing the path is a
restart. The Pricing surface reports whether the artifact it is showing you is live or waiting
for one, which is worth checking before you conclude an override is not working.

An entry looks like this:

```json
{
  "overrides": [
    {
      "key": "anthropic/claude-sonnet-4-5",
      "effective_from": "2026-09-01",
      "in": 0.0000024,
      "out": 0.000012,
      "created_by": "ops@example.com",
      "created_at": "2026-08-10T18:00:00Z",
      "status": "active",
      "note": "negotiated rate, contract 4471"
    }
  ]
}
```

Rates are dollars per token. `key` is a pricing key, and getting it right is the part people
get wrong: [pricing keys](/docs/build/providers-pricing-keys) explains how a request resolves
to one, and the Pricing surface has a dry-run match that shows you what a given model resolves
to before you commit.

You can write an override from the Pricing surface instead of by hand. Doing so needs the
operator role.

## The three rules

**An override applies from a date, never before it.** `effective_from` names an instant, and
the entry prices requests at or after it. A future-dated override is visible and browsable
now, and inert until its date arrives, which is how you land a contract change ahead of time
rather than at midnight.

**It is not retroactive.** Rows already in your ledger keep the dollars they were written
with. An override changes what the *next* request costs, and nothing about what a past one
did. That is why last month's total does not move when you correct a rate.

**A superseded rate is retired, not deleted.** Retiring an entry stops it pricing anything new
while leaving it in the artifact, so a row priced under it stays explainable. The stamp is
computed over the rate itself rather than over the entry's status, so a row priced under a
now-retired override still matches the stamp it carries.

<Callout type="key">
An override changes future prices only, and the artifact keeps every rate it ever applied. A
dollar in your ledger can always be traced to the rate that produced it, including one that is
no longer in force.
</Callout>

## How an overridden dollar identifies itself

A row priced through the embedded table carries the catalogue snapshot:

```text
litellm@2026-07-14#179affb
```

A row priced through an override carries an operator stamp instead:

```text
operator@2026-09-01#a1b2c3d
```

Source, effective date, and a short hash of the rate identity. It appears wherever a pricing
snapshot appears: in `cost.pricing_snapshot` on the ledger row, on the record, and in exports.

That is the property that makes overrides safe to use at all. Someone auditing a figure can
tell which rows were priced under a local rate and go and read that rate, rather than
wondering why a number does not match a public price list.

## Triage the unpriced rows first

<Screenshot
  stem="pricing-unpriced"
  url="localhost:9090/ui/pricing"
  alt="The Pricing surface showing the active snapshot with its source, fetch date, generator and model count, and an unpriced triage panel listing the models that appear in the ledger with no entry in the price table."
  caption="The unpriced triage lists the models your traffic used that the price table does not cover. Each is a candidate for an override (real dashboard, demo mode)."
/>

The unpriced panel is the list of models your own traffic used that the table cannot price.
Every row on it is excluded from every dollar total, so working the list down to zero is what
makes your cost figures complete rather than merely correct.

An instance with nothing to triage says so: `No unpriced rows — every logged row has a price.`

## Retiring one

Set an entry's `status` to `retired`, or use the retire action from the surface. It stops
pricing new requests immediately; nothing else changes. Do not delete the entry, because
deleting it removes the record of a rate that priced real rows, and the stamp on those rows
then points at nothing.

If the correct move is a different rate rather than none, add a new entry with a later
`effective_from` and retire the old one. The artifact then reads as a history of what you
charged yourself and when.

<Details summary="When an override is the wrong tool">

**The model has a price and you disagree with the catalogue.** Check the pricing key first. A
mismatch is more often a key resolving to a different variant than a wrong rate, and an
override on the wrong key will not fix it.

**A whole provider is missing.** That is a descriptor question rather than a price one.
[Add a provider](/docs/build/providers-custom) covers declaring an upstream, including
declaring one free.

**You want a different price per tenant.** Overrides are global to the instance. Per-tenant
economics belong to [chargeback](/docs/build/cost-attribution), which attributes the same
dollars differently rather than changing them.

**You want last month's total to change.** It will not. Overrides are forward-only, and
reprocessing history is not something this product does.

</Details>

## What can go wrong

**The override does nothing.** Three checks, in order: is the artifact live rather than
pending a restart, has `effective_from` arrived, and does the key match what the model
resolves to. The surface answers the first two, and the dry-run match answers the third.

**Rows still read as unpriced.** The key is not matching. Use the dry-run rather than
guessing at the spelling.

**An old row's snapshot names an override you cannot find.** It was retired, and it should
still be in the artifact. If it is not, somebody deleted it, and that row's provenance is now
unrecoverable — which is the reason for the retire-not-delete rule.

**Two entries cover the same key.** The one whose date has arrived most recently wins. Keep
that legible by retiring what you have superseded.

<NextSteps items={[
  {title: "Pricing keys", href: "/docs/build/providers-pricing-keys", description: "How a request resolves to the key an override has to match."},
  {title: "How to read a number", href: "/docs/build/dashboard-reading-a-number", description: "Where the operator stamp shows up, and the other markings beside a dollar."},
  {title: "Where a cost figure comes from", href: "/docs/build/cost-figures", description: "What the rate is multiplied by, and when the token counts are estimated."},
  {title: "Invoice reconciliation", href: "/docs/build/cost-reconciliation", description: "Compare your priced ledger against the bill that prompted the override."}
]} />
