Administration

Models and pricing

Publish models, configure integer pricing, and enable safe automatic routing.

Deeplinq does not maintain an independent provider-synchronized model table. Its model catalog is the governed intersection of connector capacity, runtime pricing, and organization grants.

Who decides what

Four decisions, four owners, and they are deliberately not the same decision:

DecisionOwnerSurface
The model exists and has a priceplatform administratorPUT /v1/admin/pricing/{model}
The application sells itthe applicationPUT /v1/application/models/{model}
An organization may use itplatform administratorPOST /v1/admin/orgs/{id}/models
Which of its people may use itorganization administratorPOST /v1/model-grants

A caller reaches a concrete model only when every one of them says yes. Pricing a model means the platform can bill it, never that an application sells it; offering a model does not grant it to anybody, and does not assert that a connector serves it.

Application model availability

An application decides which of the engine's concrete chat models it offers its own tenants, with its own credential and no application id in the path:

  • GET /v1/application/models lists the whole global chat catalog — the models it has not enabled included, since that is the list a model is enabled from — sorted by model, each row exactly model, provider, tier and enabled. Embedding models and the virtual auto are never listed.
  • PUT /v1/application/models/{model} offers one. It takes no body: the path is the whole request, and a payload is a 400. It is idempotent.
  • DELETE /v1/application/models/{model} withdraws one. Withdrawing something the application never offered is a 404.

The offer is an authorization ceiling, not a display preference. A tenant of the application can use a model only when the application offers it and an organization grant permits it, and the check runs in the same query as the grant — so /v1/models, chat, streaming chat and auto routing all obey it, and calling the engine directly cannot route around it.

Two rules make it safe to turn on and off:

  • Enabling never widens an organization. An organization that already restricted the model to certain roles or people keeps exactly that; only an organization with no row at all is given an organization-wide grant.
  • Disabling never erases policy. Existing grants stay stored and simply stop taking effect, so re-enabling the model restores the previous restrictions. While a model is withdrawn, new grants for it are refused and revoking an existing one still works.

Enabling and disabling also keep the application's signup defaults in step, so organizations created later start with the same access as the ones that already exist. Retiring the global pricing row withdraws the model from every application at once; re-creating the price does not restore any application's offer.

Pricing units

Machine API prices use integer micro-USD per one million tokens:

  • 1,000,000 micro-USD = USD 1;
  • input_micro_usd_per_mtok prices one million input tokens;
  • output_micro_usd_per_mtok prices one million output tokens;
  • margin_pct is applied after provider token cost;
  • tier is economy, standard, or frontier;
  • modality is chat or embedding (default chat) — see below.

The browser console presents exact decimal USD-per-million values. The machine API uses integers so ledger arithmetic never depends on floating point.

Modality

modality says what a priced model is FOR: chat (the default) or embedding. It exists because pricing a model is not the same thing as making it callable in chat — an embedding model is legitimately priced, for its own metering, and priced is the only thing the grant path used to check.

Grant an embedding model as an organization's chat entitlement and the request is now refused, naming the modality:

{
  "error": "invalid_request",
  "message": "model text-embedding-3-large is priced as embedding, not chat — org grants are chat entitlements; embedding models are used directly by the platform and are never granted to an organization"
}

An organization doing RAG does not need this grant at all — embeddings ride the platform's own connector, never an organization's model grant. Needing to grant an embedding model to an org is itself the signal something is set up wrong.

Two things follow from this:

  • modality is sticky on repricing. Every other field in a PUT is a full replacement — omit tier and it resets to standard — but omitting modality keeps the row's current value instead of resetting it to chat. Adjusting an embedding model's margin must not silently re-label it back to chat.
  • Every model priced before this field existed reads back as chat (the migration default): every model priced here before today was onboarded to serve chat traffic. Re-label an embedding model explicitly:
curl --user "$ADMIN_USER:$ADMIN_PASSWORD" \
  -H "Content-Type: application/json" \
  -X PUT "$BASE_URL/v1/admin/pricing/text-embedding-3-large" -d '{
  "provider":"openai",
  "input_micro_usd_per_mtok":20000,
  "output_micro_usd_per_mtok":0,
  "modality":"embedding"
}'

GET /v1/readiness's model-served component is also modality-aware: it checks a granted model against chat/rag/agents capacity only when that model is itself priced chat. A model priced embedding can never make those capabilities report a connector gap, even if it was granted in error.

Add or replace a price

curl --user "$ADMIN_USER:$ADMIN_PASSWORD" \
  -H "Content-Type: application/json" \
  -X PUT "$BASE_URL/v1/admin/pricing/claude-sonnet-4-5" -d '{
  "provider":"anthropic",
  "input_micro_usd_per_mtok":3000000,
  "output_micro_usd_per_mtok":15000000,
  "margin_pct":20,
  "tier":"standard"
}'

This example represents USD 3 per million input tokens and USD 15 per million output tokens before the 20% margin. Verify current upstream prices yourself; provider pricing changes independently from Deeplinq.

The next request uses the committed price. Repricing does not rewrite historical ledger entries.

Prompt-cache rates

Cached prompt tokens are billed relative to the input price: a cached read, a 5-minute cache write, and a 1-hour cache write each carry a multiplier. Every model starts on its provider family's published defaults — for example cached reads at 0.1× on both the Anthropic and OpenAI families, cache writes at 1.25× (5m) and 2× (1h) on the Anthropic family.

Some models depart from their family. OpenAI charges a cache-write premium on gpt-5.6 and later and nothing on the models beneath it, so the rate belongs to the model rather than the provider. Set it on the model's own pricing row:

curl --user "$ADMIN_USER:$ADMIN_PASSWORD" \
  -H "Content-Type: application/json" \
  -X PUT "$BASE_URL/v1/admin/pricing/gpt-5.6" -d '{
  "provider":"openai",
  "input_micro_usd_per_mtok":1250000,
  "output_micro_usd_per_mtok":10000000,
  "margin_pct":20,
  "tier":"frontier",
  "cache_write_5m_twentieths":25
}'

Multipliers are integer TWENTIETHS of the input rate, so no float touches money: 20 is 1×, 25 is 1.25×, 2 is 0.1×. Every published rate lands on that step. Omit a field (or send null) and the model inherits the family default for that class — an upsert states the whole row, so omitting a previously-set multiplier clears it. The console shows the same values as decimals ("1.25") and leaves the field blank when the family default applies.

Enter rates you have verified against the provider's published pricing. The engine never guesses a premium: an unset multiplier means the family default, not zero.

Cost model

For ordinary uncached usage:

provider cost =
  input tokens × input price / 1,000,000
  + output tokens × output price / 1,000,000

tenant debit = provider cost × (100 + margin_pct) / 100

Prompt-cache token classes are priced with provider-family multipliers when real cache usage is reported. Preflight reservations remain conservative at the full input rate, then settle against actual usage.

Partial provider usage can still be charged if a provider fails after reporting tokens. Settlement is idempotent by request ID.

List and retire

GET    /v1/admin/pricing
DELETE /v1/admin/pricing/{model}

Deleting the row stops new requests for that model at billing preflight. It does not erase connector configuration, organization grants, or historical usage.

Automatic routing

When a request specifies "model":"auto", Deeplinq:

  1. classifies prompt complexity with deterministic heuristics;
  2. optionally refines the classification with a router connector;
  3. selects the cheapest entitled model in the chosen tier.

The router never expands an organization's grants. Grant the special auto model and suitable concrete models before using it.

Use tiers intentionally:

TierIntended use
economyLow-cost extraction, classification, and simple chat
standardGeneral application work
frontierHighest-capability and complex reasoning workloads

Troubleshooting

SymptomCheck
Model absent from /v1/modelsConnector enabled, model list match, application offer (GET /v1/application/models), organization grant
model_not_pricedAdd the runtime pricing row
model_not_permittedAdd the organization grant — and check the application still offers the model; a withdrawn model leaves the grant stored but ineffective
Granting a model answers invalid_request naming the applicationThe organization's application does not offer the model; enable it with PUT /v1/application/models/{model} first
Provider rejects model nameConnector models and request ID must use the real upstream identifier
auto has no candidateGrant concrete models in the required tier and verify their prices
Granting a model answers invalid_request naming a modalityThe model is priced embedding, not chat — org grants are chat entitlements; embeddings ride the platform connector and need no grant

Log X-Request-ID with every failure; it joins provider, audit, and ledger evidence.

On this page