Detached orders
To avoid holding a connection while a low price waits, detach the request. You get 202 and an order id at once, the order waits on your behalf, and you collect the result when it is done.
Submitting
Pass detached: true on a chat or completion request. Disconnecting never cancels a detached order. Detaching does not change how long an order waits: a price-locked order still expires with its window (10 seconds), so leave the lock off for a request that must wait for a low level. stream and detached cannot be combined.
curl https://api.openfill.ai/v1/chat/completions \ -H "Authorization: Bearer $OPENFILL_API_KEY" -H "Content-Type: application/json" \ -d '{"messages": [{"role":"user","content":"hello"}], "model": "placeholder-large", "max_price": 0.05, "detached": true}'202 {"id": "<order_id>", "object": "order", "status": "queued", "expires_at": "...", "result_url": "/v1/orders/<order_id>/result", "result_stored": true, "result_retention_days": 7}| Field | Meaning |
|---|---|
| id | The order id. Every later call names it. |
| status | queued on a fresh submission. On an idempotent replay, the original order's current status. |
| expires_at | When the order leaves the book unexecuted: your timeout, or the lock window. |
| result_url | Where the body will be. |
| result_stored | Whether a result will be kept. false when storage is off for this request. |
| result_retention_days | How long it is kept, or 0. |
| warning | Present only when result_stored is false, saying the result URL will answer 410. |
Caution
Data storage is off by default, and with it off a detached result is never stored, so the result endpoint returns 410 once the order finishes. Turn it on in Settings if you intend to collect results later. The storage page has the rules.
Collecting the result
curl https://api.openfill.ai/v1/orders/<order_id>/result \ -H "Authorization: Bearer $OPENFILL_API_KEY"{"status": "done", "result": { ...the full chat completion... }}{"status": "done", "result": null, "result_pending": true} # not written yet, retry{"status": "expired", "error": "...", "result": null} # terminal, stop pollingBranch on status: it is the field that says whether the order has finished. Every answer carries id, status, created_at, expires_at and result_expires_at, then one of the shapes below.
| Order status | Answer |
|---|---|
| queued | 200 with result: null and queue_position, the order's place in the book. |
| executing | 200 with result: null. |
| done, result stored | 200 with result, the full completion body. It can be read as many times as you like until it expires. |
| done, still being written | 200 with result: null and result_pending: true, plus a Retry-After header. Poll again. |
| done, nothing stored | 410 result_unavailable. The message says whether storage was off, the result aged out, or you deleted it. |
| error, canceled, expired | 200 with result: null and a populated error. Final; nothing further will arrive. |
Poll at a gentle interval. The result endpoint shares the per-account order budget on limits, and each body read counts against the hourly download allowance there.
Deleting a stored result
DELETE /v1/orders/{id}/result removes the body from storage ahead of your retention period and answers deleted: true. Deleting is idempotent, so a retry after a dropped response is not an error, and it does not change what the request was billed: the order and its charge stay in your history. Deleting before the order has run marks it, and the result is never stored.
Two cases are refused.
| Case | What happens |
|---|---|
| The durable write has not landed yet | Refused with 409 result_write_pending until it has, with Retry-After. Deleting mid-write would leave the order pointing at a body that is gone. |
| The result belongs to a batch that is still running | Refused with 409 batch_in_progress until the batch finishes, since its output file needs it. |
Per-request storage controls
Any request may send "store": false to retain nothing durably for that call, or "retention_days": N to keep it for a shorter window than your account setting. Both can only shorten storage: your account policy is the outer bound. Lowering your account setting also shortens data already stored.
Detached and idempotent
A detached request that carries an Idempotency-Key is safe to resend: the replay answers 202 again with the same order id and the order's current status. One order exists for the key, however many times it is sent.
Following an order without its body
GET /v1/orders/{id} reports status, queue position, what the order cleared at and any error, whatever your storage setting. It is the call to make while an order waits.