Pricing Table
Technical reference. This page is for integrations, advanced configuration, or platform operations. For portal tasks, start with the user guide.
The pricing table is a platform-scoped registry of input_cents_per_million_tokens and output_cents_per_million_tokens for every (provider, model) pair Orqestra tracks. The org daily-cost pool reads this table to size each reservation; pricing edits are billing-policy events with broad blast radius, so they sit behind a separate permission (Permission.PRICING_MANAGE) auto-granted only to Role.PLATFORM_ADMIN.
The table was added in ADR 0063, backed by Alembic migration 040_governance_pricing_and_snapshot.py. The migration seeds pricing rows for the models your deployment’s model catalog registers, so first traffic post-deploy never observes pricing_unavailable for a model an operator has already approved. See Governed Providers for a worked example of registering a provider and model end to end.
What this surface does
Every cost-acquire resolves pricing cache-first (60s in-process cache, namespace ("pricing", provider, model)) then DB. A miss returns 503 pricing_unavailable and the runtime-gateway converts it to a structured decision.outcome=pricing_unavailable for the caller. The cache is invalidated automatically when an operator PUTs a new pricing row.
Each row uses an active-row supersede pattern: editing a price does not UPDATE the existing row — it INSERTs a new row and sets superseded_at on the prior active row. A partial unique index (WHERE superseded_at IS NULL) keeps exactly one active row per (provider, model) at all times. The table grows monotonically; history is queryable via the dedicated history route.
change_reason is mandatory at PUT time. The route validates min-length 1 + non-whitespace-only, the repository re-validates at the persistence layer, and the audit row carries the reason verbatim. Empty reasons return 400 change_reason_required.
Admin routes
Four routes live under /v1/governance/pricing/.... All four are platform-scoped.
| Method | Path | Permission | Purpose |
|---|---|---|---|
GET | .../pricing | GOVERNANCE_POOL_VIEW | List every active (provider, model) pricing row. |
GET | .../pricing/{provider}/{model} | GOVERNANCE_POOL_VIEW | Read active pricing for one (provider, model) pair. |
PUT | .../pricing/{provider}/{model} | PRICING_MANAGE | Supersede the active row + emit v1.governance.pricing_changed + audit row + invalidate the in-process pricing cache. |
GET | .../pricing/{provider}/{model}/history | GOVERNANCE_POOL_VIEW | Read newest-first edit history including superseded rows. |
Permission.PRICING_MANAGE is separate from GOVERNANCE_POOL_MANAGE because pricing edits have billing-policy blast radius (every cost reservation across every org reads from this table). The permission is auto-granted to Role.PLATFORM_ADMIN only via the frozenset(Permission) trick — operators with workspace-scope or org-scope governance management cannot edit pricing.
Request / response shapes
GET pricing returns:
{
"pricing": [
{
"pricing_id": "8c3a1b9e-0cae-4a63-8ad8-50ee3d5e60f1",
"provider": "your-provider",
"model": "your-provider/your-model",
"input_cents_per_million_tokens": 250,
"output_cents_per_million_tokens": 1000,
"effective_at": "2026-04-01T00:00:00Z"
}
]
}PUT pricing/{provider}/{model} body:
{
"input_cents_per_million_tokens": 250,
"output_cents_per_million_tokens": 1000,
"change_reason": "Provider announced May-1 price update; pre-staging the new rate."
}Returns the new active snapshot:
{
"pricing_id": "f6c1ab92-1e2a-4f48-9c1c-bc3a2f6a45c0",
"provider": "your-provider",
"model": "your-provider/your-model",
"input_cents_per_million_tokens": 250,
"output_cents_per_million_tokens": 1000,
"effective_at": "2026-04-27T18:14:02Z"
}400 responses:
change_reason_required—change_reasonis empty / whitespace-only.input_cents_per_million_tokens/output_cents_per_million_tokensbelow0→ 422 (Pydantic). A zero value is valid for local or internally absorbed-cost routes.
GET pricing/{provider}/{model}/history?limit=30 returns newest-first:
{
"history": [
{
"pricing_id": "f6c1ab92-...",
"provider": "your-provider",
"model": "your-provider/your-model",
"input_cents_per_million_tokens": 250,
"output_cents_per_million_tokens": 1000,
"effective_at": "2026-04-27T18:14:02Z"
},
{
"pricing_id": "8c3a1b9e-...",
"provider": "your-provider",
"model": "your-provider/your-model",
"input_cents_per_million_tokens": 200,
"output_cents_per_million_tokens": 800,
"effective_at": "2026-04-01T00:00:00Z"
}
]
}limit accepts 1..100, default 30.
Example invocations
# List every active pricing row
curl -H "Authorization: Bearer $TOKEN" \
"https://control-plane/v1/governance/pricing"# Read active pricing for a governed (provider, model) pair
curl -H "Authorization: Bearer $TOKEN" \
"https://control-plane/v1/governance/pricing/your-provider/your-model"# Supersede the active row (requires PRICING_MANAGE)
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"input_cents_per_million_tokens": 250, "output_cents_per_million_tokens": 1000, "change_reason": "2026-05-01 provider list-price update"}' \
"https://control-plane/v1/governance/pricing/your-provider/your-model"# Pull the newest-first edit history
curl -H "Authorization: Bearer $TOKEN" \
"https://control-plane/v1/governance/pricing/your-provider/your-model/history?limit=30"The same operations are wrapped by the CLI: orqestractl pricing list, orqestractl pricing get, orqestractl pricing put, orqestractl pricing history.
Defaults and configuration
Pricing-related variables on the control-plane Settings:
| Variable | Default | Purpose |
|---|---|---|
ORQESTRA_PRICING_CACHE_TTL_SECONDS | 60 | Per-worker TTL on the ("pricing", provider, model) cache namespace. PUT pricing invalidates by key. |
Pricing rows themselves have no default — the migration seeds pricing for the models your deployment’s model catalog registers at deploy time, and operators add new rows via PUT as new providers / models come online.
Reservation snapshot semantics
Pricing changes do not retroactively re-price open reservations. Each cost-acquire copies the active pricing snapshot into the reservation row at acquire time (Audit P0 #6). A mid-flight pricing supersede affects only acquires AFTER the supersede; existing RESERVED rows commit against their frozen snapshot.
This is the load-bearing invariant for ledger correctness: an operator who updates pricing while traffic is in flight does not produce a “we billed the customer at the old rate but charged the budget at the new rate” mismatch.
Where a price applies
In the portal, Cost > Pricing shows each model’s active price. Expanding a row lists the workloads that spent at that price over the last 30 days, or since the first full day after it took effect, across the workspaces you can view. It also shows 10% of that priced spend, which is the cost of a 10% price change. Calls with no price or not yet settled are counted but never estimated. Spend for earlier versions is not tracked.
Operator alerts
The pricing surface itself does not fire any standalone Prometheus alerts. Pricing edits are explicitly logged via two channels:
v1.governance.pricing_changedevent — best-effort emission post-supersede withbefore/afterattribute blocks pluschange_reason. Subscribers can react to a price change in near-real-time (e.g. update a downstream cost dashboard, page a billing operator on a > 2x price increase).governance.pricing.changedaudit row — durable, hash-chained, never redactable per spec §4.2. Carriessubject_id=<provider>:<model>plus the same before/after/change_reasonpayload.
The pricing_lookups_total{provider, model, source} counter exports the cache hit/miss rate; a sudden cliff in cache hits typically indicates either a new model handle the table doesn’t know about or a pricing edit invalidating the cache repeatedly. See Cost & Pricing Recovery Runbook Shape 2 for the audit procedure when a pricing_changed event needs investigation.
Related
- Org Daily Cost — every cost acquire reads from the pricing table; the snapshot is frozen into the reservation row.
- Provider TPM Pools — the throttle-side companion to cost; TPM does not consult the pricing table directly.
- Cost & Pricing Recovery Runbook — operator runbook for stuck reservations, pricing audits, anomaly investigation, and snapshot reruns.
- Audit & Compliance — every pricing edit lands in the hash-chained audit log; chain verification proves the edit history has not been tampered with.
- ADR 0063 — Provider TPM and organization daily cost pools .