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:
| Decision | Owner | Surface |
|---|---|---|
| The model exists and has a price | platform administrator | PUT /v1/admin/pricing/{model} |
| The application sells it | the application | PUT /v1/application/models/{model} |
| An organization may use it | platform administrator | POST /v1/admin/orgs/{id}/models |
| Which of its people may use it | organization administrator | POST /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/modelslists the whole global chat catalog — the models it has not enabled included, since that is the list a model is enabled from — sorted bymodel, each row exactlymodel,provider,tierandenabled. Embedding models and the virtualautoare never listed.PUT /v1/application/models/{model}offers one. It takes no body: the path is the whole request, and a payload is a400. It is idempotent.DELETE /v1/application/models/{model}withdraws one. Withdrawing something the application never offered is a404.
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_mtokprices one million input tokens;output_micro_usd_per_mtokprices one million output tokens;margin_pctis applied after provider token cost;tieriseconomy,standard, orfrontier;modalityischatorembedding(defaultchat) — 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:
modalityis sticky on repricing. Every other field in aPUTis a full replacement — omittierand it resets tostandard— but omittingmodalitykeeps the row's current value instead of resetting it tochat. 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) / 100Prompt-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:
- classifies prompt complexity with deterministic heuristics;
- optionally refines the classification with a
routerconnector; - 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:
| Tier | Intended use |
|---|---|
economy | Low-cost extraction, classification, and simple chat |
standard | General application work |
frontier | Highest-capability and complex reasoning workloads |
Troubleshooting
| Symptom | Check |
|---|---|
Model absent from /v1/models | Connector enabled, model list match, application offer (GET /v1/application/models), organization grant |
model_not_priced | Add the runtime pricing row |
model_not_permitted | Add 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 application | The organization's application does not offer the model; enable it with PUT /v1/application/models/{model} first |
| Provider rejects model name | Connector models and request ID must use the real upstream identifier |
auto has no candidate | Grant concrete models in the required tier and verify their prices |
Granting a model answers invalid_request naming a modality | The 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.