OpenFill is in development. Inference is off, but is tested end to end, and will switch on at launch. All data currently on the site is for live testing: it will be erased at launch.

Skip to content
openfill

Market data

Every figure the site draws is served here, without a key: the level of each market, the quote, the history, the probes and the limits. Read it before you have an account.

Public endpoints are rationed per address, 600 requests a minute, and answer 429 with Retry-After past that. The three streams share a cap of 5 open connections per address; this cap sends no Retry-After. Every market ?model= defaults to the default model. Uptime and token statistics pool models when it is absent. A model that is not served is 400 with code unknown_model, and a fixed-price model on a market endpoint is 400 fixed_price_model. A preview of the market answers every market endpoint from prices simulated until it opens, and says so with preview: true.

Models and rate limits

GET /v1/models
curl https://api.openfill.ai/v1/models
json
{"object": "list", "default": "market-preview", "reference_mix": {"cached_share": 0.9, "uncached_share": 0.1, "output_per_input": 0.02}, "data": [{"id": "market-preview", "object": "model", "created": 1735689600, "owned_by": "openfill", "display_name": "market-preview",           "context_length": 262144, "max_output_length": 128000,           "pricing_ratio": {"cached": 1, "uncached": 10, "output": 20},           "pricing": {"type": "market"}, "preview": true}]}

Every served model, in configured order, with the weights that share a level across the three token kinds and the two length limits. reference_mix is what fixes the level's unit. A fixed-price model's pricing_ratio is its three prices.

FieldMeaning
pricing.typemarket on a market model, or fixed on a fixed-price model. Read a value you do not recognise as a model with no static price.
pricing.usd_per_millionFixed only: the three prices, {cached, uncached, output}, in USD per 1M tokens of cache-hit input, cache-miss input and output.
pricing.levelFixed only: those prices at the reference mix, in the price limit's unit, which is the figure bid and level_at_execution carry on the model's receipts. It moves only when the prices do.
pricing.prompt, completion, input_cache_readFixed only: the cache-miss, output and cache-hit prices as decimal strings in USD per token, for a reader that expects pricing.prompt.
previewtrue on a preview of the market, which opens soon. Its market endpoints serve prices simulated until then, and a request to it answers 400 model_preview with nothing charged. Read a missing field as false.
GET /v1/models/{model}
curl https://api.openfill.ai/v1/models/market-preview

One entry from the same list, by id or by alias, which is what an OpenAI SDK's models.retrieve calls. An alias carries x_alias_of naming its model. A model that is not served is 404 with code model_not_found.

GET /v1/rate-limits
curl https://api.openfill.ai/v1/rate-limits

Every ceiling, as enforced, in the shape the rate limits page renders.

The level

GET /v1/market
curl "https://api.openfill.ai/v1/market?model=market-preview"
json
{"model": "market-preview", "level": 0.023, "usd_per_million": {"cached": 0.01, "uncached": 0.1, "output": 0.2}, "mode": "preview", "degraded": false, "updated_at": "2026-09-01T12:00:00.000Z", "preview": true}
FieldMeaning
levelUSD per 1M input tokens at the reference mix. It can reach 0 when capacity exceeds demand; the published level moves toward its target.
usd_per_millionThe same level as the three prices it implies, per 1M tokens of each kind.
modeclearing in normal operation, and preview on a preview of the market.
degradedtrue when no pod is healthy. The level is then frozen and orders queue. Always false on a preview of the market.
updated_atWhen the level last moved.
previewtrue on a preview of the market, whose level is simulated until it opens; a request to the model answers 400 model_preview. Read a missing field as false.

A fixed-price model has no level. Every /v1/market route answers it with 400 fixed_price_model, whose message points at GET /v1/models, and the all-markets read and stream below leave it out.

Every market at once

GET /v1/market/levels
curl https://api.openfill.ai/v1/market/levels
json
{"levels": [{"model": "market-preview", "level": 0.023, "preview": true}, ...]}

A preview market's row carries preview: true.

Streams

Two server-sent event streams, each a data: frame per change and a repeat of the current values as a keepalive while nothing moves. There is no event name, so an EventSource receives them as messages.

GET /v1/market/stream?model=
data: {"level": 0.023, "usd_per_million": {...}, "updated_at": "..."}
GET /v1/market/levels/stream
data: {"levels": [{"model": "...", "level": 0.023, "updated_at": "..."}, ...]} data: {"levels": [{"model": "...", "level": 0.024, "updated_at": "..."}]}

The all-markets stream opens with every market and then sends only the market that moved; the keepalive repeats the whole set, so a missed delta is corrected within it. Merge by model. A frame for a preview of the market carries preview: true on either stream.

The quote

GET /v1/market/price-lock
curl "https://api.openfill.ai/v1/market/price-lock?model=market-preview"
json
{"price": 0.025, "previous_price": 0.024, "usd_per_million": {"cached": 0.010869565, "uncached": 0.108695652, "output": 0.217391304}, "valid_until": "...", "valid_for_ms": 30000, "interval_ms": 60000, "execute_window_seconds": 10, "clear_rate": null, "clear_rate_window_ms": 600000, "target_start_rate": 0.95}
FieldMeaning
priceThe quote in the level's unit. A locked request bids the lower of this quote and its own price_limit at submission.
previous_priceThe quote of the window before. Null until a second window has been latched.
valid_until, valid_for_msWhen this quote stops standing, and how long that is from now.
interval_msHow long every quote stands.
execute_window_secondsHow long one locked request has to start, from its own submission.
clear_rateThe measured share of locked requests with a price limit above the quote that started inside their window. Null below the sample floor.
clear_rate_window_msHow far back clear_rate was measured.
target_start_rateWhat the margin is calibrated toward, over the same population.
GET /v1/market/price-lock/stream?model=
data: {"price": 0.025, "previous_price": 0.024, "usd_per_million": {...}, "valid_until": "..."}

One frame per window boundary, plus the keepalive.

A preview market's quote is published from its simulated level by the same rules. Nothing locked runs on it, so its clear_rate is null.

History and candles

GET /v1/market/history
curl "https://api.openfill.ai/v1/market/history?model=market-preview&range=24h"
json
{"range": "24h", "model": "market-preview", "bucket_seconds": 43, "from": 1756641600, "to": 1756728000, "current": 0.023, "points": [{"t": "2026-09-01T00:00:00.000Z", "level": 0.0221}, ...]}
FieldTypeDefaultMeaning
modelstringthe default modelOne served model.
rangestring24h1h, 24h, 7d or 30d. Anything else is served as 24h, and the response says which.

Each point is the time-weighted mean level over its bucket, whose width is chosen so a range holds about two thousand points. Buckets with no reading are absent. from and to are epoch seconds aligned to the bucket, for the axis. History is kept for the longest range.

GET /v1/market/ohlc
curl "https://api.openfill.ai/v1/market/ohlc?model=market-preview&range=24h&bucket=300"
json
{"range": "24h", "model": "market-preview", "bucket_seconds": 300, "bucket_choices": [60, 300, 900, 1800, 3600, 7200], "current": 0.023, "candles": [{"t": 1756641600, "open": 0.022, "high": 0.024, "low": 0.021, "close": 0.023, "mean": 0.0226}, ...]}

bucket is snapped to the nearest choice at or below it, and a request below the smallest choice uses that smallest choice. An absent or invalid bucket does the same. bucket_choices lists the widths the range can carry. t is the bucket start in epoch seconds; mean is time-weighted like history.

On a preview market both are computed from the same simulated prices as its level, on the same buckets.

Uptime probes

GET /v1/uptime
curl "https://api.openfill.ai/v1/uptime?range=24h&model=market-preview"
json
{"range": "24h", "model": "market-preview", "bucket_seconds": 1800, "interval_ms": 300000, "checks_running": true, "degraded": false, "summary": {"total": 288, "failures": 1, "uptime_pct": 99.65,             "avg_ms": 812, "max_ms": 4100, "avg_queue_ms": 120, "max_queue_ms": 900, "avg_pipeline_ms": 690, "max_pipeline_ms": 3300}, "buckets": [{"t": 1756641600, "total": 6, "failures": 0, "avg_ms": 800, ...}, ...]}

Every interval_ms the gateway sends a real completion through the whole pipeline for each model that is ready, and records whether it came back and how long it took. Without ?model= the figures pool every model. range is 24h, 7d or 30d, defaulting to 24h for any other value.

FieldMeaning
checks_runningWhether the probe is recording for this model now. false with an empty series means unmeasured rather than down.
degradedtrue when no pod of the model is healthy now, or with no model named, when no model served has one. Read live, like checks_running. Always false on a preview of the market.
uptime_pctThe share of probes that returned. Null with no probes in the range.
avg_queue_ms, max_queue_msTime the probe spent in the book, which is demand rather than health.
avg_pipeline_ms, max_pipeline_msEverything else: admission, generation, metering and billing. This is the part that is up or down.

A router that times out a queued request counts it as an error, so a third party's uptime figure for OpenFill can sit below the probe's while its own price limits are low.

Token statistics

GET /v1/stats/tokens
curl "https://api.openfill.ai/v1/stats/tokens?range=24h"
json
{"range": "24h", "model": null, "bucket_seconds": 3600, "from": 1756641600, "to": 1756728000, "series": [{"model": "market-preview", "points": [{"t": 1756641600, "input_tokens": 1000, "cached_tokens": 900, "miss_tokens": 100, "output_tokens": 50, "requests": 7}]}]}

The range parameter accepts 24h, 7d or 30d and otherwise uses 24h. The optional model filter selects one model or alias. Billed tokens per model per bucket, with the probe's own traffic left out. cached_tokens is a subset of input_tokens, so stack hits and misses to get input. Only models and buckets with traffic appear.

GET /v1/stats/models
curl "https://api.openfill.ai/v1/stats/models?range=7d"
json
{"range": "7d", "top": "market-preview", "default": "market-preview", "models": ["market-preview", ...], "data": [{"model": "market-preview", "level": 0.023, "pricing": {"type": "market"}, "degraded": false, "preview": true, "input_tokens": 0, "cached_tokens": 0, "miss_tokens": 0, "output_tokens": 0, "total_tokens": 0, "requests": 0}]}

One row per model, deprecated ones and zeros included, ranked by what each market earned over the window; top is the first of them, and models is the configured order. The board on the landing page reads this ranking.

Fixed-price models follow the market rows, in configured order, and top is always a market model. Each row carries pricing, as on GET /v1/models, and degraded, true when no pod of the model is healthy now. A fixed-price row's level is null.

A preview market's row carries preview: true beside its simulated level, and its token counts stay at zero until it opens.

Partner catalog

GET /openrouter/v1/models
curl -i https://api.openfill.ai/openrouter/v1/models

The data array uses the provider catalog schema and quotes decimal strings in USD per token, derived for a market model from the standing price lock quote and its ratio. This differs from the clearing level on /v1/market. Set price_lock: true and a price_limit to submit under a quote; reading the catalog alone does not lock a request. A fixed-price model is listed at its own three prices. A preview of the market is left out until it opens.

HeaderMeaning
Cache-Controlmax-age ends at the soonest quote expiry among the market models, or at the next quote boundary when every model listed is fixed-price.
X-Price-Valid-UntilThat expiry as an ISO timestamp. Refresh before submitting under a later window.
X-Price-Window-SecondsThe configured quote interval.

The is_ready field reports whether a model is offered for traffic. The catalog can retain a deprecated entry with is_ready false. compliance.zdr reflects the content retention declared for the model's serving capacity; your own account storage settings still apply.

Liveness

GET /healthz
curl https://api.openfill.ai/healthz
json
{"ok": true, "db": true, "market_loop": true, "role": "clearing", "level": 0.023, "queued": 12, "inflight": 3, "backend_healthy": true, "pods": 3, "healthy_pods": 3, ...}

200 when the database answers and the market loop is healthy; standby and draining roles also satisfy the loop check. Otherwise it answers 503. Backend and object storage failures are reported separately and do not change ok.

Discovery and redirects

GET /api/hello and HEAD /api/hello answer 200 for client discovery. GET /v1/limits redirects to /v1/rate-limits with 308. The health and partner catalog routes have separate behavior from the public market request budget above.