# Market data

> The Markdown form of https://openfill.ai/docs/api/market. The index of every docs page is https://openfill.ai/llms.txt, and every page in one file is https://openfill.ai/llms-full.txt.

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**

```bash
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.

| Field | Meaning |
| --- | --- |
| pricing.type | market 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_million | Fixed only: the three prices, {cached, uncached, output}, in USD per 1M tokens of cache-hit input, cache-miss input and output. |
| pricing.level | Fixed 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_read | Fixed only: the cache-miss, output and cache-hit prices as decimal strings in USD per token, for a reader that expects pricing.prompt. |
| preview | true 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}**

```bash
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**

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

Every ceiling, as enforced, in the shape the [rate limits page](https://openfill.ai/docs/rate-limits) renders.

## The level

**GET /v1/market**

```bash
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}
```

| Field | Meaning |
| --- | --- |
| level | USD 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_million | The same level as the three prices it implies, per 1M tokens of each kind. |
| mode | clearing in normal operation, and preview on a preview of the market. |
| degraded | true when no pod is healthy. The level is then frozen and orders queue. Always false on a preview of the market. |
| updated_at | When the level last moved. |
| preview | true 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**

```bash
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=**

```bash
data: {"level": 0.023, "usd_per_million": {...}, "updated_at": "..."}
```

**GET /v1/market/levels/stream**

```bash
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**

```bash
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}
```

| Field | Meaning |
| --- | --- |
| price | The quote in the level's unit. A locked request bids the lower of this quote and its own price_limit at submission. |
| 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 price limit 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. |

**GET /v1/market/price-lock/stream?model=**

```bash
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**

```bash
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}, ...]}
```

| 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.

**GET /v1/market/ohlc**

```bash
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**

```bash
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.

| Field | Meaning |
| --- | --- |
| checks_running | Whether the probe is recording for this model now. false with an empty series means unmeasured rather than down. |
| degraded | true 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_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 price limits are low.

## Token statistics

**GET /v1/stats/tokens**

```bash
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**

```bash
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**

```bash
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.

| Header | Meaning |
| --- | --- |
| Cache-Control | max-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-Until | That expiry as an ISO timestamp. Refresh before submitting under a later window. |
| X-Price-Window-Seconds | The 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**

```bash
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.

Previous: [Files and batches](https://openfill.ai/docs/api/batches).
