Bifrost

Responses

POST /v1/responses and its persisted-state siblings — the OpenAI Responses contract.

curl -X POST "$GATEWAY/v1/responses" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "general", "input": "Say hi" }'

Same canonical core as Chat completions, rendered through the Responses shape: input instead of messages, text.format instead of response_format, reasoning: { effort, summary } instead of reasoning_effort, plus multi-turn state the client doesn't have to resend by hand.

input_file accepts provider file IDs, HTTPS URLs, and base64 data. Native transports receive the original file form when possible; Gemini URLs are materialized to inline data, and text-only deployments receive an explicit parser fallback. See Content inputs.

input_image likewise accepts HTTPS or base64 data URLs. The same candidate-aware resolver preserves native URLs where supported and securely materializes them for inline-only transports, so historical images remain portable when a Responses conversation is replayed through another provider.

The router prefers the native Responses transport when a deployment supports it. Inputs that only exist on this wire, such as built-in tools or native item types, are preserved verbatim and require a native deployment; they are never silently erased during conversion to another text protocol.

Persisted state

Unlike Chat Completions, a Response can be stored and referenced later:

  • store (boolean) — whether to persist this response. Defaults to RESPONSES_STORE_DEFAULT (gateway-wide, true by default; set false gateway-wide for a privacy-first deployment) when the client omits it.
  • previous_response_id — chains a new request onto a previously stored one: the gateway reconstructs the full input (the previous request's input + its output) and prepends it, so the client only sends the new turn. Returns 400 previous_response_not_found if the referenced id doesn't exist or belongs to a different virtual key — stored state is scoped per key, the same way rate limits and budgets are.
  • GET /v1/responses/:id — retrieve a previously stored response.
  • GET /v1/responses/:id/input_items — list the resolved input items (including anything inherited via previous_response_id).
  • DELETE /v1/responses/:id — delete stored state early, before its retention window (RESPONSES_STATE_RETENTION_DAYS) expires it automatically.

Stored state lives in Postgres (response_states), separate from observability tables — it exists to reconstruct conversation state, not for observability. See Environment variables for the retention variable and Operations → response_states GC for how expiry actually runs.

When store: false, the client owns the full conversation state. Echo output items back as they were returned: opaque provider state rides inside function calls and reasoning items, so clients that replay ids and items verbatim need no provider-specific handling. Encrypted reasoning content is included in the public response only when include requests it; internal persisted state retains it for faithful continuation. See Provider-specific fields.

Compaction

POST /v1/responses/compact accepts model plus input, previous_response_id, instructions, and prompt_cache_key. It returns a response.compaction resource whose opaque output item can be sent back in a later Responses request. The capsule is encrypted locally, contains a concise continuation summary rather than the full transcript, and is expanded only by the same gateway instance.

text.format

Maps to the same canonical responseFormat as Chat Completions' response_formattext, json_object, or json_schema. See Chat completions → Structured outputs.

Reasoning

reasoning: { "effort": "high", "summary": "auto" } — the object form of the same canonical knob described in Reasoning. summary controls whether the model's reasoning is surfaced back (auto, none, concise, detailed).

responsesTransport passthrough

Fields specific to the Responses wire contract that don't have a Chat Completions equivalent — include, metadata, service_tier, safety_identifier, prompt_cache_key, top_logprobs, max_tool_calls, truncation, context_management, and user — are threaded through as-is to providers that support the Responses transport natively. Response resources include the complete nullable and defaulted field set required by the current OpenResponses resource schema.

Streaming

Same SSE mechanics as every other endpoint. Terminal upstream failure events are surfaced as errors, and a stored stream is committed before its terminal success event is emitted. See Streaming.

WebSocket mode

Open a persistent connection to wss://YOUR_GATEWAY/v1/responses using the same bearer key as HTTP. Each turn starts with a top-level response.create object:

{
  "type": "response.create",
  "model": "general",
  "store": false,
  "input": "Find the bug"
}

Do not send the HTTP-only stream, stream_options, or background fields. Server messages are the normal JSON response.* streaming event objects, without SSE framing. A connection processes one turn at a time; additional response.create messages are queued in arrival order. Open another connection for parallel runs.

The connection keeps the most recent response state in memory. Continue with only new items and its public id:

{
  "type": "response.create",
  "model": "general",
  "store": false,
  "previous_response_id": "resp_...",
  "input": [
    {
      "type": "function_call_output",
      "call_id": "call_...",
      "output": "tool result"
    }
  ]
}

This works with store: false while the socket remains open. After reconnecting, only store: true responses can be hydrated from Postgres; otherwise send the complete context or a compacted window. Connections close after 60 minutes with websocket_connection_limit_reached.

generate: false performs an OpenAI-compatible warmup. Providers without native Responses WebSockets receive a gateway-local semantic warmup. When the selected OpenAI deployment supports the native transport, the gateway maintains a separate upstream socket and private upstream response id. Public ids and events are still regenerated through the canonical core; provider traffic is never passed directly to the client.

  • Chat completions — the fields shared between both contracts.
  • Reasoning — the reasoning object in full.
  • Security — why stored responses are scoped per virtual key.

On this page