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

Chat and completions

Two endpoints, one handler. A chat request is the OpenAI shape with a price limit; a completion request is the legacy shape, remapped to a single user message on the way to the model.

Create a chat completion

POST /v1/chat/completions
curl https://api.openfill.ai/v1/chat/completions \  -H "Authorization: Bearer $OPENFILL_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "market-preview", "messages": [{"role": "user", "content": "hi"}], "price_limit": 0.10}'

Request body

The OpenAI fields first, then the OpenFill extensions. Optional scalar fields accept null as absent. A field absent from this table is forwarded to the model untouched, except the identifiers listed below.

FieldTypeDefaultMeaning
modelstringthe default modelA served model id. GET /v1/models lists them.
messagesarrayrequiredAt least one message with a nonempty role. Content can be a string, an array of parts, null or absent. Tool calls, tool results and name pass through.
streambooleanfalseServer-sent events. The response is 200 once the order is queued.
stream_optionsobjectnone{include_usage: true} adds a final chunk carrying usage and x_market.
max_tokens, max_completion_tokensintegerthe model's max outputPositive integers up to 10000000. max_tokens takes precedence. The selected cap is clamped down to the model's max output length.
temperaturenumbernone0 to 2.
top_pnumbernone0 to 1.
stopstring or arraynoneUp to four strings of up to 256 characters.
n, best_ofinteger1Must be 1. Anything else is refused with 400.
tools, tool_choiceas OpenAInoneForwarded to the model. Calls are assembled from the stream and returned whole.
response_format, seedas OpenAInoneForwarded to the model untouched.
user, safety_identifier, metadata, prompt_cache_keyas OpenAInoneAccepted and kept on our side. These fields are removed before execution; content inside messages and tools is sent to the model.
logprobs, top_logprobsas OpenAInoneForwarded. The response carries choices[0].logprobs.
price_limitnumberkey or accountThe most you will pay, in USD per 1M input tokens at the reference mix (90% cached, 2% output). The range is 0 to 1000000000. A bid of 0 can run when capacity reaches it and is charged nothing. On a market model, none anywhere is 400 missing_price_limit. Ignored on a fixed-price model, whose prices are under pricing on GET /v1/models.
price_lockbooleanaccount settingOnly for a request whose price has to be known before sending. Bid the lower of the published quote and price_limit. Starts within 10 seconds or expires with 429 capacity_unavailable. Ignored on a fixed-price model, whose price is known before the request is sent; that request waits up to its order timeout.
max_waitintegeraccount settingSeconds an unlocked order may wait, 10 seconds to 30 days. Alias expires_after. The schema accepts 1 to 2592000; values outside that range or fractions are 400. Within it, the wait is clamped to the configured range. max_wait takes precedence over expires_after. A lock uses its own window after validation.
detachedbooleanfalseAnswer 202 with an order id and run in the background. Refused with 400 alongside stream.
storebooleanaccount settingfalse keeps nothing durable for this request.
retention_daysintegeraccount settingA nonnegative integer. Clamped down to the account setting; 0 keeps no result or request log. store: false takes precedence.

Response

The OpenAI chat.completion object with exactly one choice, and usage.x_market added.

json
{  "id": "chatcmpl-...", "object": "chat.completion", "created": 1756700000, "model": "market-preview",  "choices": [{    "index": 0,    "message": {"role": "assistant", "content": "...", "reasoning_content": "..."},    "finish_reason": "stop",    "logprobs": null  }],  "usage": {    "prompt_tokens": 12, "completion_tokens": 40, "total_tokens": 52,    "prompt_tokens_details": {"cached_tokens": 8},    "x_market": {"order_id": "<order_id>", "pricing": "market", "level_at_execution": 0.0143, "bid": 0.1, "charged_usd": 0.000005272}  }}
FieldMeaning
message.contentThe answer. null for a turn that is only tool calls.
message.reasoning_contentA reasoning model's chain of thought, when the model sends one.
message.tool_callsPresent when the model called tools.
logprobs{content: [...]} when you asked for logprobs, else null.
usage.x_market.order_idThe order id used by every /v1/orders route, also in x-openfill-order-id. Older stored results can omit this field.
usage.x_market.level_at_executionThe price the order was charged at: the level at dispatch, or the bid where that was lower. On a fixed-price model, its prices at the reference mix, in the price limit's unit.
usage.x_market.bidWhat the order rested at: your price limit, or the lower of the quote and your price limit when locked. On a fixed-price model, the same figure as level_at_execution.
usage.x_market.charged_usdThe debit, in USD to nine decimal places.
usage.x_market.pricingmarket, or fixed on a fixed-price model. Older stored results can omit this field, which reads as market.
usage.x_market.usd_per_millionOn a fixed-price model only: the three prices applied, per 1M tokens of cache-hit input, cache-miss input and output.

Response with detached: true

json
202 {  "id": "<order_id>", "object": "order", "status": "queued", "expires_at": "...",  "result_url": "/v1/orders/<order_id>/result",  "result_stored": true, "result_retention_days": 7}

warning is added when nothing will be stored. The detached orders page has the collection semantics.

Response with stream: true

200 and a text/event-stream body: queue comments while the order waits, the model's chunks, a usage chunk when asked for, and data: [DONE]. Every frame is on the streaming page.

Statuses this endpoint answers

StatusWhen
200The completion, or a stream.
202detached: true, once the order is queued.
400Malformed body, n or best_of above 1, missing_price_limit, invalid_output_cap, model_deprecated, model_preview on a preview of the market, a bad X-Price-Limit or X-Expires-After, or a request the model refused.
401, 403The key, or the account behind it.
402insufficient_balance at the current level, or at a fixed-price model's prices.
404model_not_found.
408order_expired: the wait on a market model passed max_wait.
409order_canceled while it waited, or idempotency_error on a mismatched replay.
410result_unavailable on a replay of a finished order with nothing stored.
413The body is over the size limit.
429rate_limit_error on a ceiling, capacity_unavailable on a missed lock window or when a request to a fixed-price model did not start before max_wait, result_pending on a replay still being stored.
500, 502, 503Our side, the backend mid-stream, or the backend unavailable. A settlement error may leave the charge uncertain; check the order and usage before repeating the work.

Create a completion

POST /v1/completions
curl https://api.openfill.ai/v1/completions \  -H "Authorization: Bearer $OPENFILL_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "market-preview", "prompt": "Say hi", "price_limit": 0.10}'

The same handler and the same extensions, with the legacy shape's differences:

FieldOn /v1/completions
promptA string, or an array of one string. It becomes a single user message. Absent, it is empty.
tools, tool_choice, functions, function_callRefused with 400: the response has nowhere to put a call.
logprobs, top_logprobs, echo, suffixRemoved before the model sees them. The response has logprobs: null.
max_completion_tokensRead as the output cap when max_tokens is absent; a non-integer or a value under 1 is 400 invalid_output_cap on that path.
json
{  "id": "cmpl-...", "object": "text_completion", "created": 1756700000, "model": "market-preview",  "choices": [{"index": 0, "text": "...", "finish_reason": "stop", "logprobs": null}],  "usage": {"prompt_tokens": 4, "completion_tokens": 2, "total_tokens": 6,            "x_market": {"order_id": "<order_id>", "pricing": "market", "level_at_execution": 0.0143, "bid": 0.1, "charged_usd": 4.97e-7}}}

Streaming on this endpoint sends text_completion chunks with choices[0].text, and the same queue comments and usage chunk as chat.