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
curl https://api.openfill.ai/v1/models{"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.
curl https://api.openfill.ai/v1/limitsEvery ceiling, as enforced, in the shape the limits page renders.
The level
curl "https://api.openfill.ai/v1/market?model=placeholder-large"{"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"}| Field | Meaning |
|---|---|
| level | USD per 1M input tokens at the reference mix. 0 when the market is idle. |
| usd_per_million | The same level as the three prices it implies, per 1M tokens of each kind. |
| mode | clearing in normal operation. |
| degraded | true when no pod is healthy. The level is then frozen and orders queue. |
| updated_at | When the level last moved. |
Every market at once
curl https://api.openfill.ai/v1/market/levels{"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.
data: {"level": 0.023, "usd_per_million": {...}, "updated_at": "..."}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
curl "https://api.openfill.ai/v1/market/price-lock?model=placeholder-large"{"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}| Field | Meaning |
|---|---|
| price | The quote a locked request bids this window, in the level's unit. |
| previous_price | The quote of the window before. Null until a second window has been latched. |
| valid_until, valid_for_ms | When this quote stops standing, and how long that is from now. |
| interval_ms | How long every quote stands. |
| execute_window_seconds | How long one locked request has to start, from its own submission. |
| clear_rate | The 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_ms | How far back clear_rate was measured. |
| target_start_rate | What the margin is calibrated toward, over the same population. |
data: {"price": 0.025, "previous_price": 0.024, "usd_per_million": {...}, "valid_until": "..."}One frame per window boundary, plus the keepalive.
History and candles
curl "https://api.openfill.ai/v1/market/history?model=placeholder-large&range=24h"{"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}, ...]}| Field | Type | Default | Meaning |
|---|---|---|---|
| model | string | the default model | One served model. |
| range | string | 24h | 1h, 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.
curl "https://api.openfill.ai/v1/market/ohlc?model=placeholder-large&range=24h&bucket=300"{"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
curl "https://api.openfill.ai/v1/uptime?range=24h&model=placeholder-large"{"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.
| Field | Meaning |
|---|---|
| checks_running | Whether the probe is recording for this model now. false with an empty series means unmeasured rather than down. |
| uptime_pct | The share of probes that returned. Null with no probes in the range. |
| avg_queue_ms, max_queue_ms | Time the probe spent in the book, which is demand rather than health. |
| avg_pipeline_ms, max_pipeline_ms | Everything 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
curl "https://api.openfill.ai/v1/stats/tokens?range=24h"{"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.
curl "https://api.openfill.ai/v1/stats/models?range=7d"{"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
curl https://api.openfill.ai/healthz{"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.