Provider Pricing Operations
Generating, reviewing, and importing signed provider pricing artifacts
Esta página aún no está disponible en tu idioma.
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.
Generate and validate artifacts
Section titled “Generate and validate artifacts”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.
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.txtGeneration 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:
nexus-registry-generator from-csv \ --provider nexus_mock \ --catalog catalog.csv --rates rates.csv \ --output dist/catalogs/custom.jsonColumn 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.
Review and import
Section titled “Review and import”One command imports one provider artifact:
just registry-import dist/catalogs/openai.json \ --expected-key-id registry-production \ --verifying-key-path registry-verifying-key.txtIt 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.
Quarantine recovery
Section titled “Quarantine recovery”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.
Validation and settlement
Section titled “Validation and settlement”Run the offline artifact gates from nexus/:
cargo test -p nexus-registry-artifactcargo test -p nexus-registry-generatorcargo test -p nexus-registry --test import_change_set_migrationpython3 -m unittest discover -s test-suite/billing -p 'test_*.py'python3 test-suite/billing/validate_pricing.py --provider both --bands bothpython3 test-suite/billing/reconcile.py --sidecar test-suite/billing/reports/<run>.requests.jsonThe 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.
Rollback and convergence
Section titled “Rollback and convergence”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.
