Skip to content
Pre-launch — the gateway is being built now

Change two lines. Route every model.

public.supply is an OpenAI-compatible inference router that shows its work: the tier it picked, every provider it tried, and what the request actually cost.

The numbers we can stand behind

lines you change

2

baseURL and apiKey. Nothing else moves.

task classes measured

17

A closed vocabulary, extended only by amendment.

models per multi-mode run

10

One prompt, one reservation, one stop button.

conformance assertions

65

C1–C65. Reddening one rejects the pull request.

There are no traffic figures here because there is no traffic yet. Every number above is a property of the specification or the repository, and it is checkable — which is the only kind of number worth putting on a landing page.

The migration

Two lines, and your existing code is on the router.

The official openai SDKs for TypeScript and Python work against our endpoint with no change beyond baseURL and apiKey. Fields OpenAI accepts are accepted and never rejected. Everything of ours is additive: strip every Supply-specific field and the request still runs.

Your client — the whole diff
 import OpenAI from "openai";  const client = new OpenAI({-  baseURL: "https://api.openai.com/v1",-  apiKey: process.env.OPENAI_API_KEY,+  baseURL: "https://public.supply/api/v1",+  apiKey: process.env.SUPPLY_API_KEY, });  const res = await client.chat.completions.create({   model: "anthropic/claude-sonnet-4.5",   messages: [{ role: "user", content: "Summarise this." }], });
What comes back — response shape
 "model": "anthropic/claude-sonnet-4.5", "usage": { "total_tokens": 60, "cost": 0.000225 }, "supply": {   "routing": {     "servedProvider": "bedrock/us-east-1",     "attempts": [       { "provider": "anthropic-direct", "error": "429", "ms": 120 },       { "provider": "bedrock/us-east-1", "ok": true, "ms": 80 }     ]   },   "cost": {     "cogsMicros": 180,     "chargedMicros": 225,     "marginRuleId": "rule_default"   } }

What we do not claim, said here rather than in a support ticket: byte-identical completions, or OpenAI-account resources such as fine-tuning, assistants and vector stores. Those return a clearnot_supportedtelling you what to use instead — never a confusing 404. The claim is kept honest by a conformance suite that installs the real openai packages and runs a scripted corpus against our server on every merge.

Why this exists

Four things a gateway usually gets wrong.

A router that actually routes

Most turns in an agent loop are routine, and they get answered by whatever model the top of the loop picked. A cheap triage model reads the request first and chooses the tier; a pure heuristic gate resolves the obvious cases without a classifier call at all. Name a model and you get that model — triage never re-routes a named request.

Provenance, not opinion

Every quality number in the capability matrix carries its source, method, date, sample size and model version. A cell with no provenance is unknown, and an unknown cell is not allowed to influence routing. Anyone can assert a ranking; the method is the part worth publishing.

The real cost, every time

Each response carries integer micros, the underlying cost of goods, and the id of the margin rule that produced the charge. Money never crosses a boundary as a float, and a charge you cannot attribute to a named rule is a charge you cannot defend in a dispute.

Failures that tell the truth

A 401 means your key is bad and nothing else. A cold cache, a dead catalog or a wallet timeout is a 503 that says overloaded — not an authentication error that costs you a day rotating perfectly good keys, and never a price we quietly made up.
Contracts, not slogans

Each of these is a test that blocks a merge.

The right-hand column is the assertion or invariant that holds the promise up. If a later feature conflicts with one of them, the contract wins.

ContractWhat it meansHeld up by
Cancellation stops billingA client disconnect aborts the upstream call and settles at the tokens actually produced. Where a provider cannot be aborted, the receipt says estimated_uncancellable instead of charging you as though it ran to completion.C52
No silent failoverEvery attempt is enumerated in the response with its provider, its error and its milliseconds. Failover is allowed before the first byte, capped at three attempts. After the first byte, nothing switches.C4 · I3
A 401 is only ever a bad key401 is emitted only after a successful lookup returns a definitive answer. A failed cache, catalog or wallet read is 503 overloaded, classified twice — in the adapter and again at the edge.C1 · C2 · I2
We never invent a priceA catalog or pricing lookup that fails is a 503, not a silent default. Charging you against a guessed number is worse than failing the request.I2
Money is an integerInteger micros of USD end to end, with one conversion point in the codebase. Rounding is always ceil when we charge you and always floor when we credit you.I1
A hard ceiling fails closedmax_price rejects candidates rather than overspending. Latency and throughput preferences only reorder them. The distinction is stated at every mention because guessing wrong about it shows up on an invoice.C56
The capability matrix

Tiers are computed, never typed.

A tier table someone wrote from memory in March is a liability by June. Ours is a versioned table of model against task class, where a model can be large for code generation and small for chitchat — which is the entire point, and something one global tier column cannot express.

Every metric carries source, method, measuredAt, sampleSize and modelVersion. Nothing is published yet: no cells are seeded, and until a cell has provenance it stays unknown and cannot influence routing. It is still available to anyone who asks for that model by name.

17 task classes

closed vocabulary
  • chitchat
  • simple_qa
  • classification
  • extraction
  • summarization
  • translation
  • rewriting
  • structured_output
  • code_generation
  • code_review
  • math_reasoning
  • long_context_reasoning
  • agentic_tool_use
  • creative_writing
  • vision_ocr
  • vision_reasoning
  • safety_sensitive
qualityScore
The tier axis.
instructionFollowing
A model that ignores format instructions is useless in a pipeline.
jsonValidityRate
Gates structured output outright.
toolCallSuccessRate
Gates agentic tool use — the most common real failure.
refusalRate
A cheap model that refuses is not cheap.
contextDegradation
Where accuracy actually falls off, well below the advertised window.
p50TtftMs
The latency term.
p50TokensPerSec
The throughput term.
blendedCostPerMTokens
The savings term.
Multi-mode

One prompt, up to ten models, side by side.

Pick the targets, send the prompt once, and watch the columns stream as answers arrive rather than after the slowest model finishes. Attachments upload once and are shared across every leg.

One reservation

A fan-out is up to a tenfold cost multiplier, so the whole run reserves against the sum of its legs up front and each leg settles its own share. Ten racing balance checks is not a design.

One stop button

Stop all cancels every in-flight leg together; cancelling a single column aborts that upstream request alone and leaves the other nine running.

One failure is not the run

A model that fails the capability pre-filter is greyed out with a reason before you submit, not surfaced as a broken stream after. The run completes when every leg reaches a terminal state.
Stream events
  • run.start
  • stream.start
  • stream.delta
  • stream.usage
  • stream.error
  • stream.done
  • run.done

Point an OpenAI client at it and read the receipt.

Sign in with Google, mint a key, and buy credits. The gateway is still being wired; the account, wallet and keys are live now.