Skip to content
↑↓Navigate↵SelectescClose

Provider Pricing Operations

Generating, reviewing, and importing signed provider pricing artifacts

Nexus stores provider pricing as append-only, effective-dated rate cards and qualified rate rows. Each rate identifies provider, canonical model, service tier, context threshold, meter, billing unit, modality, qualifiers, effective interval, and source hash.

nexus-registry-generator collects the OpenAI and Anthropic catalogs into one offline artifact JSON per provider. Each file is the complete catalog for its provider at generation time: a catalog table (one row per model, with capabilities and aliases) and a rates table (one row per priced meter, with context bands and effective intervals), plus the source evidence and an optional Ed25519 signature. Prices in rates are USD per million tokens for token meters — the same figures the provider’s pricing page publishes — so a reviewer can compare a row against the source directly.

Terminal window
just registry-generate \
--generated-at 2026-07-23T12:00:00Z \
--artifact-id provider-catalog-2026-07-23 \
--signing-key registry-signing-key.txt \
--key-id registry-production \
--output dist/catalogs
just registry-import dist/catalogs/openai.json --check \
--expected-key-id registry-production \
--verifying-key-path registry-verifying-key.txt

Generation prints each artifact’s content SHA-256 digest. --check performs strict decoding, reference and pricing-contract validation, and prints the same digest without using a database or network. The digest and signature bind the parsed content through its canonical serialization, so a hand-edited file may use any field order or whitespace — any content change still invalidates them. Unsigned artifacts are accepted by default. Pass --expected-key-id with --verifying-key-path to require a signature from a trusted key; a signed artifact is never accepted without them.

For isolated networks and custom provider sources, author the catalog and rates as CSVs and convert them into the same signed artifact form:

Terminal window
nexus-registry-generator from-csv \
--provider nexus_mock \
--catalog catalog.csv --rates rates.csv \
--output dist/catalogs/custom.json

Column templates live under tools/registry-generator/templates/.

For Azure AI Foundry, foundry-csv writes that CSV pair from a live resource’s deployment listing, and --prices fills the rates from the published Azure pricing pages wherever the model name and SKU scope match a published row exactly; see Azure AI Foundry connections.

For AWS Bedrock, bedrock-csv writes that CSV pair from a live account’s foundation-model listing for one region, and --prices fills the rates from the public AWS Price List bulk API wherever the publisher and model names match a published on-demand product exactly; see AWS Bedrock connections.

OpenAI publishes its prices through three surfaces on one page, and the collector reads all three: the server-rendered tables, which alone carry the computed long-context (>=272K input tokens) columns; those tables’ component props, which carry every text model including the ones the page renders client-side; and the grouped props tables, which carry per-modality image pricing and the category tables (embeddings, ChatGPT, Codex). Where two surfaces state the same model, tier, modality, and context band they must agree on the amount, and a disagreement fails generation. Anthropic web-search calls are collected as source-backed tool_call rates at the published USD-per-call price and qualified with tool_type=web_search. The generator attaches that rate to every eligible Anthropic catalog model, matching the provider-reported usage.server_tool_use.web_search_requests meter the gateway settles. Figures the contract cannot express — per-minute audio, per-second video, fine-tuning training hours, and Free — are not collected.

A model ships enabled only when the supported-pricing manifest lists it as supported and its default service tier is fully priced: input and output tokens for chat and responses models, input tokens for embeddings, and text input plus image input and output for image models. A model that clears the manifest but lacks that coverage ships disabled and non-routable with disabled:incomplete-active-tier-pricing in its classification evidence, which is the first thing to check when a model you expected is missing from the catalog.

Every name a pricing source prices must be classified in the manifest, because rate collection keeps only rows whose model is a catalog entry. Generation fails listing any priced name the catalog does not carry, so declining to serve one is an unsupported classification with a stated reason rather than an omission. Classify a key alias only when it is a second name for another model’s endpoint: same upstream model, same published price, no behavioural difference the provider documents. An alias is removed from the catalog and attached to its target’s aliases[], which also discards any price published under that name — so a key that merely happens to be priced the same as another model is its own model and belongs under supported. No shipped manifest key is an alias today.

Fixture generation accepts --fixture-dir; it generates the fixture artifacts twice and fails if any output byte differs. Mapping a Foundry deployment to a connection remains a separate provider-connection operation. The artifact contract accepts a routable catalog row for commercial Bedrock; every bedrock-gov row must be explicitly non-routable.

One command imports one provider artifact:

Terminal window
just registry-import dist/catalogs/openai.json \
--expected-key-id registry-production \
--verifying-key-path registry-verifying-key.txt

It validates the artifact, diffs it against the provider’s current registry state, prints the plan, and asks for confirmation before writing anything. The provider comes from the artifact itself. --dry-run prints the plan and writes nothing; --yes skips the prompt for non-interactive callers. Declining, --dry-run, and an artifact that changes nothing all leave the registry untouched.

Behind the prompt, the plan is a durable change set. Preparing it persists the provider baseline, deterministic changes, findings, source provenance, schema and contract versions, generator identity, signature metadata, and digests; confirming binds a short-lived approval to the artifact SHA-256, baseline hash, provider revision, findings digest, artifact schema version, import contract version, generator name, and generator version. Hard-reject findings block the import outright. JSON output (--format json) is the complete change set record — the plan when nothing was applied, the applied result otherwise.

Apply uses only the artifact retained by prepare; it never recollects provider data. It acquires a provider-scoped Postgres advisory transaction lock and row lock, then revalidates the stored artifact, signature policy, approval hash and expiry, baseline hash, provider revision, changes, and findings. It writes endpoints, cards, rates, activations, revision state, audit staging, and the applied status in one transaction. A lock conflict, stale baseline, expired or altered approval, changed artifact, contract mismatch, malformed rate, or missing required rate fails closed without a partial registry update.

Applying an artifact whose rate set, activation interval, normalized source interval, and default service tier match an existing active card reuses that card. Material pricing changes insert a new card and qualified rates and supersede the overlapping activation. Database triggers make rate cards and qualified rate rows immutable after insertion; they are never updated or deleted. Each imported card and rate retains its source change-set identifier and normalized source-effective interval.

Effective dates and unsupported dimensions

Section titled “Effective dates and unsupported dimensions”

Rate matching uses the request timestamp and exact effective interval. Intervals are lower-bound inclusive and upper-bound exclusive. Overlapping active rows are invalid. Historical request cost lines retain rate-card IDs and source hashes, so a later rate change does not rewrite earlier charges.

The supported-pricing manifest under crates/nexus-registry/tests/fixtures/pricing is the capability boundary. Observable supported meters must match an exact qualified rate. Unsupported request modes are rejected before provider dispatch. Time-accrued or provider-unobservable dimensions are marked unsupported and are not represented as zero-cost request lines.

When a successful provider response contains usage that cannot be priced, Nexus returns the provider result and stores the raw usage and typed failure in model_registry_billing_failures. The request is not charged: a pass-through-billing escrow hold settles at $0. The failure alone does not change the endpoint’s routing.

The ingest billing-health evaluator reads request analytics over a closed window and marks an endpoint degraded when its failures reach both NEXUS_BILLING_QUARANTINE_MIN_FAILURES and NEXUS_BILLING_QUARANTINE_MIN_RATIO_BPS of its priced and failed requests. With NEXUS_BILLING_QUARANTINE_ACTION=block it sets the endpoint’s pricing_status to quarantined with reason billing_health and a timestamp; with allow it records the degraded state and routing continues. There is no separate endpoint-quarantine table. PTB and BYOK routing exclude a quarantined endpoint once the gateway’s next registry reload picks it up. Below the thresholds, and until that reload, unpriceable requests keep being served without charge; see threat-model row D5 (../security/threat-model.md).

A blocked endpoint receives no traffic, so it cannot re-qualify on its own. Restore an evaluator-owned block with nexus models unquarantine <provider>/<model>. A quarantine recorded with any other reason is a structural pricing defect: recovery requires importing an artifact that covers the endpoint. Applying it sets the imported endpoint back to eligible; the normal gateway Postgres poll converges each process to the committed registry state. Do not clear the endpoint quarantine columns directly.

Run the offline artifact gates from nexus/:

Terminal window
cargo test -p nexus-registry-artifact
cargo test -p nexus-registry-generator
cargo test -p nexus-registry --test import_change_set_migration
python3 -m unittest discover -s test-suite/billing -p 'test_*.py'
python3 test-suite/billing/validate_pricing.py --provider both --bands both
python3 test-suite/billing/reconcile.py --sidecar test-suite/billing/reports/<run>.requests.json

The Rust artifact, generator, and migration gates are offline and no-cost. The ignored artifact_import_postgres integration test exercises deterministic prepare, approval binding, atomic apply, quarantine recovery, pinned pricing, and full-replace retirement against a migrated Postgres database. The gateway gate (validate_pricing.py) requires a healthy stack, query credentials, and live provider keys; see test-suite/billing/README.md for the authoritative flag reference and credential setup. Settlement (reconcile.py) requires NEXUS_BILLING_RECONCILE=1 and exits 0 pass, 1 fail, 2 pending, and 3 not configured.

Each artifact is the complete catalog for its provider: applying it replaces that provider’s registry state, and a model absent from the artifact is retired. Every retirement appears as an explicit retire row in the prepared plan with an approval-required finding, so nothing disappears without a reviewer seeing it; pinned endpoints are never retired by an import. Retired rate cards and qualified rates supersede their activations while retaining the historical card and rate rows.

There is no in-place undo. Correct an applied artifact by importing a new compensating artifact, which plans and approves against the current baseline. Never edit migration history, mutate historical pricing rows, or reuse an approval for a different artifact or baseline.

Gateways load the committed registry from Postgres at startup and replace their in-memory snapshot on the GATEWAY_REGISTRY_POLL_SECONDS interval (60 seconds by default). No restart or registry event is required. A failed poll retains the previous snapshot and retries on the next interval.