A named TierUp tier is a stable contract, not a moving target. The model class, price, and free status behind a tier don't change silently. Every change is versioned, announced here in advance, machine-checkable via GET /v1/tiers/changelog, and CI physically refuses to let a tier drift without an entry.
When a tier's backing composition has to change, we publish the entry before it takes effect — never after:
Entries carry both a published date (when notice starts) and an effective date (when the change applies), so a future-dated entry is advance notice you can act on now.
No changes yet.
Every tier is at its genesis composition (version 0). This isn't a placeholder — it's the truthful state of the contract: nothing has moved since launch. When something does, it appears here first, with notice, and this page stops saying "no changes yet."
| Tier | Class | Version | Last changed |
|---|---|---|---|
| tier-1 | Speed (free) | 0 | — |
| tier-2 | Balance | 0 | — |
| tier-3 | Intelligence | 0 | — |
| tier-4 | Reasoning | 0 | — |
tier_version and last_changed are also returned per tier on GET /v1/models, so your client can detect a moved tier without diffing this whole record.
This is a guarantee of advance notice and a replayable record — not a promise that a tier's exact outputs never change. Model serving shifts under everyone; if you need bit-exact reproducibility, pin a specific dated model with a provider that offers it. What a tier buys you is that its class won't move without an entry here, ahead of time, so you can re-baseline your own evals on a schedule you control instead of being surprised.
A named tier's material composition: the model class it resolves to, its per-token price, and whether it's free. If any of those change, there is a versioned entry here first — published at least 14 days before a material adverse change takes effect (7 days for a minor reprice). The tier name you code against stays a stable contract; the thing behind it can only move on the record, with notice.
Poll GET /v1/tiers/changelog — it returns the same machine-readable record this page renders (an OpenAI-list-shaped array, newest first). Diff it against what you last saw. Every /v1/models tier also carries tier_version (count of recorded changes) and last_changed, so you can cheaply detect "did my tier move?" without diffing the whole log.
CI enforcement. The build physically refuses to let a tier's model/price/is_free drift away from genesis-plus-changelog without a matching entry — the drift check runs on every push. So "a tier can't change without an entry here" is a property the build system enforces, not a policy we remember to follow.
No — and we won't claim that. Model serving shifts under everyone, and pinning an exact dated snapshot is table stakes you can already get elsewhere. What this gives you is different: advance notice and a replayable record of when a tier's backing class changes, so you can re-baseline your own evals on a schedule you control instead of being surprised. If you need bit-exact reproducibility, pin a specific model with a provider that offers it.
Auto-routers change what they pick silently, per request, by design — there's nothing to gate an eval against. A tier is only a differentiator if it's a contract: same class tomorrow as today unless an entry here says otherwise, ahead of time. That's the trade — you give up picking the exact model, and in return the thing you depend on stops moving without warning.
Also see: Tiers & pricing · Chat completions API · TierUp vs OpenRouter
Code against a tier that won't move under you.
The playground at tierup.ai/try works without signing up. If you like it, signup gets you $25 in credit, no card required.