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. Every ?model= defaults to the default model, and a model that is not served is 400.

Models and limits

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

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.

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

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

The level

GET /v1/market
curl "https://api.openfill.ai/v1/market?model=placeholder-large"
json
{"model": "placeholder-large", "level": 0.023, "usd_per_million": {"cached": 0.01, "uncached": 0.1, "output": 0.2}, "mode": "clearing", "degraded": false, "updated_at": "2026-09-01T12:00:00.000Z"}
FieldMeaning
levelUSD per 1M input tokens at the reference mix. 0 when the market is idle.
usd_per_millionThe same level as the three prices it implies, per 1M tokens of each kind.
modeclearing in normal operation.
degradedtrue when no pod is healthy. The level is then frozen and orders queue.
updated_atWhen the level last moved.

Every market at once

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

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.

The quote

GET /v1/market/price-lock
curl "https://api.openfill.ai/v1/market/price-lock?model=placeholder-large"
json
{"price": 0.025, "previous_price": 0.024, "usd_per_million": {"cached": 0.0109, "uncached": 0.1087, "output": 0.2174}, "valid_until": "...", "valid_for_ms": 41234, "interval_ms": 60000, "execute_window_seconds": 10, "clear_rate": 0.96, "clear_rate_window_ms": 600000, "target_start_rate": 0.95}
FieldMeaning
priceThe quote a locked request bids this window, in the level's unit.
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 max price 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.

History and candles

GET /v1/market/history
curl "https://api.openfill.ai/v1/market/history?model=placeholder-large&range=24h"
json
{"range": "24h", "model": "placeholder-large", "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=placeholder-large&range=24h&bucket=300"
json
{"range": "24h", "model": "placeholder-large", "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 bucket_choices lists the widths the range can carry. t is the bucket start in epoch seconds; mean is time-weighted like history.

Uptime probes

GET /v1/uptime
curl "https://api.openfill.ai/v1/uptime?range=24h&model=placeholder-large"
json
{"range": "24h", "model": "placeholder-large", "bucket_seconds": 1800, "interval_ms": 300000, "checks_running": true, "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.

FieldMeaning
checks_runningWhether the probe is recording for this model now. false with an empty series means unmeasured rather than down.
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 max prices 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": "placeholder-large", "points": [{"t": 1756641600, "input_tokens": 1000, "cached_tokens": 900, "miss_tokens": 100, "output_tokens": 50, "requests": 7}]}]}

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": "placeholder-large", "default": "placeholder-large", "models": ["placeholder-large", ...], "data": [{"model": "placeholder-large", "level": 0.023, "input_tokens": 0, "cached_tokens": 0, "miss_tokens": 0, "output_tokens": 0, "total_tokens": 0, "requests": 0}]}

One row per served model, 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.

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 ticking, else 503 with the same body. A down backend leaves it 200: orders queue until the pods return, which is the product working.