Skip to content
Get an API key

Reference

Updated

Compatibility and versioning

Which parts of the Responses API the helping.io API does not implement, where it differs, and the versioning policy for the surface.

Which parts of the Responses API this API does not implement, where it behaves differently, and the versioning policy. Which clients work, and how to point them here, is on Clients and SDKs.

Anything not listed as available on these pages is not on the wire. The items below are the ones a Responses API client is most likely to reach for.

Each is a 400 naming the field, so nothing is silently dropped. The wait window a background request would have outlived is 90 seconds, and a stored response is removed by deleting it: Retrieve and delete.

FieldWhat happens instead
backgroundNot accepted. Send the request without it: a non-streaming request that outlives its wait window returns the response in progress, and you retrieve it later with GET /v1/responses/{id}.
includeEach value either returns its data or is refused. reasoning.encrypted_content adds each reasoning item's encrypted content to the response. message.output_text.logprobs returns log probabilities on a model that produces them and is refused, naming the model, on one that does not; no current model produces them. file_search_call.results, web_search_call.results, web_search_call.action.sources and code_interpreter_call.outputs name hosted tools this API does not offer, and computer_call_output.output.image_url names the computer tool, which is not offered either, so each is refused. message.input_image.image_url is refused for the reason image input is: image input is not accepted, because only text reaches the model.
reasoningNot accepted; omit it. Reasoning effort is fixed by the configuration your request runs on and cannot be set per request. Reasoning output still streams and is stored, so you read it the same way.
storeNot accepted. Every response is stored, which is what makes continuing a conversation and retrieving a response work. To remove one, delete it with DELETE /v1/responses/{id}: it can no longer be retrieved, and later turns no longer send it to the model or count it against the context window.

Two more things are refused that are not request fields, so they are not in the table above.

What Status
input_image, input_file, input_video parts, and summary_text, reasoning_text or refusal parts in a message A 400 naming the part, on a response’s input and on items you add to a conversation. Only text reaches the model, so send what it needs as an input_text part: a file’s text, or a description of an image
message items with role assistant, system, or developer On POST /v1/responses only: send the user turn only. See How input becomes a turn. The Conversations API accepts all four roles, which is how you seed a history that started elsewhere

The fields below are applied when the model supports them. Support differs from model to model, so a setting the model does not support, or a value outside the range it supports, is a 400 that names the model and the field, before the response starts. For example, a model that reasons by effort does not support temperature or top_p. None of these settings is accepted and then dropped.

FieldWhat happens
frequency_penaltyApplied when the model supports it. The response reports the value it was generated with, and 0 when none was applied.
parallel_tool_callsApplied when the model supports it: false asks for at most one tool call per turn. The response reports the value it was generated with, and true when none was set.
presence_penaltyApplied when the model supports it. The response reports the value it was generated with, and 0 when none was applied.
temperatureApplied when the model supports it, within the model's range. A model that reasons by effort does not support it. The response reports the value it was generated with, and 1 when none was set.
textIts format sets the output shape, and a json_schema format constrains the output to the schema it carries, which it must include. Its verbosity sets how much detail to aim for. Each is applied when the model supports it, and the response reports the format and verbosity it was generated under.
top_logprobsNo current model returns log probabilities, so a request that sets it is a 400 naming the model and the field. The response reports 0.
top_pApplied when the model supports it, within the model's range. A model that reasons by effort does not support it. The response reports the value it was generated with, and 1 when none was set.

On a Claude model that thinks within a token budget, temperature or top_p is also a 400 before the response starts when thinking is on. Any other condition belongs to the model provider: when it refuses, the response fails, its status is failed, and error carries the provider’s reason.

The response reports each value it was generated with. Where no value was set, it reports the specification’s default: 1 for temperature and top_p, true for parallel_tool_calls, 0 for both penalties, and text for text.format.type.

A text.format of type json_schema constrains the output to the schema you supply, and must carry one: a json_schema format without a schema is a 400.

Which of the settings above each model accepts, and the range it accepts them in. A setting a model’s row does not list is a 400 for that model, before the response starts. The table is generated from the models this API serves, by the same check a request meets, so it changes when a model’s support does.

ModelSettings it accepts
anthropic/claude-fable-5parallel_tool_calls, text.format
anthropic/claude-fable-5-1parallel_tool_calls, text.format
anthropic/claude-opus-4-8parallel_tool_calls, text.format
anthropic/claude-opus-5-5parallel_tool_calls, text.format
anthropic/claude-sonnet-5parallel_tool_calls, text.format
anthropic/claude-sonnet-5-5parallel_tool_calls, text.format
google/gemini-3.1-flash-litetemperature (between 0 and 2), top_p (between 0 and 1), presence_penalty, frequency_penalty, text.format
google/gemini-3.5-flashtemperature (between 0 and 2), top_p (between 0 and 1), presence_penalty, frequency_penalty, text.format
google/gemini-3.5-flash-litetemperature (between 0 and 2), top_p (between 0 and 1), presence_penalty, frequency_penalty, text.format
google/gemini-3.6-flashtemperature (between 0 and 2), top_p (between 0 and 1), presence_penalty, frequency_penalty, text.format
google/gemini-3.7-flashtemperature (between 0 and 2), top_p (between 0 and 1), presence_penalty, frequency_penalty, text.format
google/gemini-3.8-flashtemperature (between 0 and 2), top_p (between 0 and 1), presence_penalty, frequency_penalty, text.format
openai/gpt-5.4-miniparallel_tool_calls, text.format, text.verbosity (one of low, medium, high)

These are accepted and never refused, because ignoring one of them changes nothing about the answer you get back. What each asks for is not done here yet, and the response says so rather than repeating your value: it reports what was applied. That report is a fact about the response, not a missing field. It is how you tell that the setting did not take effect, and the day one of them does take effect the same field is how you will tell that too.

FieldWhat happens, and what the response reports
prompt_cache_keyYour key does not route the provider cache, and the response reports it as null. Caching still happens, keyed by the conversation, so a continued conversation keeps its cached prefix without you sending anything.
service_tierThere is one tier. Asking for another runs on that one, and the response always reports that one tier rather than the tier you asked for.
Path Status
POST /v1/chat/completions Not available. The API speaks the Responses API, which OpenAI introduced in 2025 as the successor to Chat Completions. If your app uses Chat Completions today, OpenAI’s guide on moving to Responses covers the changes, and the same code works against this API once migrated
POST /v1/responses/compact Not available. Long conversations are not compacted on request; start a new conversation when you want a fresh context
GET /v1/responses/{id}/input_items Not available. Read the conversation’s items instead: Conversations
/v1/embeddings, /v1/completions, /v1/files Not available. This API serves the Responses API only. Use your provider directly for embeddings, and send file content as text in your input
WebSocket transport Not available. The API is HTTP and server-sent events only. For token-by-token output, set stream: true and read the SSE body: Streaming

truncation is applied, and it behaves as the Responses API describes: disabled, the default, refuses a turn that does not fit the model’s context window, and auto drops the oldest turns so the turn can proceed. Five differences are worth knowing before you rely on either value.

Difference What it means for you
The size of a turn is estimated, not tokenized The estimate reads about four characters per token. To stay safe, a turn must fit in the window left after the reply’s max_output_tokens, less 15 percent of it, less 2000 tokens for the platform’s own instructions and the estimated size of your tools. So a turn near the model’s real limit can be refused although a token count would have fit it
auto drops whole turns from the oldest end, never part of one The oldest end is the end the Responses API documents dropping from, so that much is the same
The turn you just sent is never dropped If it alone does not fit, the request fails rather than being emptied. This is our guarantee, not a shared one: the Responses API documents nothing about which items auto may keep
auto trims further than it strictly needs to It frees 10 percent of the usable budget beyond what the turn requires, so the next few turns fit without dropping anything more. Trimming to the line would drop a turn on every turn after the first, and each drop costs you the cached prefix
A refused turn is not stored The conversation is left exactly as it was, so you can send a shorter turn against the same previous_response_id

The refusal is a 400 with the code context_length_exceeded, which is the code OpenAI’s own clients branch on, and a message naming the window and the estimate. Match the code rather than the message. Retrieving a stored response reports the truncation the turn actually ran under.

One thing worth knowing before you build on either value: OpenAI marked truncation deprecated, in favor of a compaction setting this API does not implement. Read from their published API description on 2026-09-21, at revision ddface9b. It is applied here, and any change to that would follow the versioning policy below.

Behavior that differs from what you might expect

Section titled “Behavior that differs from what you might expect”
  • No stream resume. Last-Event-ID is not honored, and starting_after is refused with a 400 rather than ignored, so a client that asks to resume learns that it cannot. If a stream drops, retrieve the response by id or retry the request with the same Idempotency-Key.
  • Some declared stream events are never sent, among them the reasoning summary ladders. Each one, and what arrives in its place, is listed under Events you will not receive.
  • Where a refusal’s words arrive depends on the model’s provider. When a model declines, its message gains a refusal content part after any text it already produced, and the response completes, as OpenAI reports a refusal. For Anthropic models, the part’s refusal text is the model’s explanation when it gives one. For OpenAI models, the words of the refusal arrive first as ordinary output_text, and the part’s refusal text is empty. For Google models, the part’s refusal text is empty.
  • max_tool_calls counts every tool call. OpenAI applies it to built-in tools only. Here it counts every call the model makes while generating the response, your own function tools included. Your organization’s policy also limits how many calls one turn may make. Calls past either limit are neither returned nor run, and helpingio:tool_calls_dropped on the response says how many were cut. When you send function call outputs, the response that continues from them starts a new count. A value below 1 is a 400.
  • safety_identifier reaches only providers with a field for it. It is sent, as a keyed hash of your value, to models whose provider has a per-end-user field, and not to Google models, which have none. The response still reports the value you sent, and helpingio:warnings says when it was not sent. The deprecated user is used in its place when it is absent.
  • Cancel works on any response your key created, not only one created with background: true. See Cancel a response.
  • Retrieval is live, not a snapshot. GET /v1/responses/{id} reflects the response’s current state.
  • When you answer a tool call, resent history is ignored rather than appended. Client libraries usually resend the whole transcript alongside the function_call_output. Those items are already in the conversation, so this API acts on the tool output and ignores the rest, where OpenAI appends what you send. The result is the same conversation without a second copy of the same exchange. On a new conversation there is nothing to duplicate, so a function_call sent with its matching function_call_output is carried in as real history.
  • A retrieve reports what the response ran under, not what you sent. metadata, previous_response_id, truncation and instructions come back as you sent them. model comes back as the model that ran, and max_output_tokens as the limit that applied, which is lower than you asked for when the model’s own maximum is lower. tools and tool_choice come back as the first turn of the conversation set them, because a turn that answers a tool call runs with the settings of the turn that asked: this API ignores tools, tool_choice, max_tool_calls and safety_identifier when you send tool output, as the standard function-calling loop does when it re-sends your request body. So if you changed any of them while answering a tool call, the retrieve reports the earlier values, which are the ones the model actually had. The response that continues from your tool output counts its tool calls from zero against that same max_tool_calls.
  • previous_response_id names the turn a response continues, not always its immediate predecessor. Answering a tool call produces a new response without starting a new turn, so every response of one turn reports the same previous_response_id: the response that turn continued. Walking the chain backwards therefore steps over the tool-answer responses in between. Use the conversation’s item list to read a turn’s full history in order.
  • There is no way to change a response’s metadata after it is created. That is not a limitation of this API: the Responses API has no update-response route at all, so metadata is set once with the response. A conversation’s labels can be replaced, through POST /v1/conversations/{id}.
  • metadata is never sent to a model, on a response as on a conversation. It is storage and labeling, not instruction.
  • A response reports conversation only when you named one. Send conversation and the response carries that id, on the create, on the stream and on a later retrieve. Send none and it is null, even though your history is still kept for you, because a conversation you did not ask for is not one you can use.
  • Deleting is a tombstone, and it keeps your billing records. Both DELETE /v1/responses/{id} and DELETE /v1/conversations/{id} stop the data being readable at once, and erase its content 30 days after the delete, without destroying what you were charged or the record of the calls that produced it. Deleting the same thing twice is not an error. There is no undelete.
  • A deleted response also disappears from its conversation’s items. It stops being readable, stops being continuable through previous_response_id, and its messages and tool calls drop out of GET /v1/conversations/{id}/items. The rest of the conversation is untouched.
  • A response still running omits usage. The field appears once the response settles, so read it with a presence check rather than expecting null. Completed and failed responses carry it, and so does a response that ends in a function call.
  • usage counts the whole exchange, not one turn. A conversation that runs through several tool rounds reports the running total every time, so the figure grows as you go and the last one is what the exchange cost. It is not a per-turn breakdown, and subtracting two of them is not one either.
  • Error codes are this API’s own, not OpenAI’s. response.error.code and the code in an error envelope come from this API’s own catalog, such as provider_overloaded or insufficient_credits. Match on the HTTP status and the error type when you need behavior that works against both APIs. One code is shared on purpose: insufficient_quota, with OpenAI’s own type and code, for an organization that cannot pay for the request. The full list is on the Errors page.
  • created_at on a conversation is Unix seconds, matching the Responses API’s own convention for the field.
  • Only items you added can be removed from a conversation. Removing an item a response produced is a 400; delete the conversation instead.
  • Two kinds of history never appear in a conversation’s item list: a server-side tool failure, and response lifecycle. A response reports its own tool failures as items; the conversation’s list does not. See What the item list does not show.
  • strict on function tools is echoed but not enforced. Check each function_call’s arguments against your schema in your own code before you run the tool.
  • function_call_output.status is ignored, and a failure you report in a tool output counts as a completed tool call. Say that the tool failed in the output text, which the model does read.

The API implements the Open Responses specification; the OpenAI SDKs are clients that work with it. Every wire response and stream event is validated against a pinned schema before a change can ship, so the shapes on this surface are the ones your SDK already expects. There is one prefix on the API, /v1, and the rules below say what a client can build against without watching for announcements.

Where this surface and OpenAI’s differ, the difference is listed on this page. A field the API does not implement is accepted and ignored, or refused with a 400 in OpenAI’s own error shape that names it.

  • Unknown request fields never fail a request. No wire type rejects unknown fields. A field is rejected only when it asks for behavior the API cannot honor, and then with a 400 that names it, which is what lets a newer SDK keep working against this surface.
  • An unknown value of a known field is a 400 that names it. An item type, a service_tier or a tool type this API does not define is refused, with the field in param and its path, such as input[1], in the message. The message quotes the value when it is a short name rather than free text.
  • Extensions are namespaced. Everything beyond the specification carries the helpingio: prefix and never changes an enum, union, or required field of it. See Extensions.
Breaking, would require a new prefix Compatible, may land under /v1
Removing or renaming any field, status value, event type, or error code a client validates against the schema A new helpingio: field
Changing the meaning of an existing one A new error code under an existing HTTP status
Narrowing what is accepted A loosened acceptance rule
A new endpoint