Docs · OpenAI-compatible API
Responses
The OpenAI Responses dialect, the default of the newest OpenAI SDKs. This gateway implements the stateless part: you send the input, you get one answer, and nothing is kept. Anything that needs the server to remember or to act returns 501.
POST/v1/responses#
- Auth and limit: like chat completions: your API key, and the shared
/v1request limit. - Body: JSON, with
Content-Type: application/json.
curl -s "$SHVIA_URL/v1/responses" \
-H "Authorization: Bearer $SHVIA_API_KEY" -H "Content-Type: application/json" \
-d '{
"model": "'"$SHVIA_MODEL"'",
"instructions": "Answer in one sentence.",
"input": "What is a gateway?"
}'Request#
| Field | Notes |
|---|---|
model | required. A model id from models |
input | required. A string, or an array of messages. Up to 200 items, and up to 200000 characters in a string |
instructions | optional string, used as the system message, at most 200000 characters. It is echoed in the response |
collections | optional list of 1 to 5 ids of your collections. The pieces of them that bear on the question are added to the system message, and are not echoed in instructions. Refusals use error.code, and the headers X-Inference-Collections and X-Inference-Excerpts say what was used |
stream | true for server-sent events |
reasoning.effort | minimal or low become low; medium and high are kept; other values are ignored |
metadata | optional object, echoed in the response |
store | accepted. The response always says "store": false |
max_output_tokens, temperature, top_p, truncation, parallel_tool_calls, user, service_tier and similar | accepted and ignored |
An array input holds messages with a role of user, assistant, system or developer (the last two both become system), and a content that is a string or a list of input_text, output_text or text blocks. The input must contain at least one user message, or the call returns 400.
What returns 501#
These are refused, with the body shown below, before the model is chosen:
| Field | Why |
|---|---|
previous_response_id | no conversation state is kept |
tools, tool_choice, include | function calling is not part of this slice. Any tool_choice, even "auto", is refused; tools: [] passes |
background set to true | no background runs |
text.format other than plain text | no structured output |
input items other than messages, such as function_call, function_call_output, reasoning or item_reference | no state to refer to |
input_image, input_file, input_audio content blocks | not supported |
{
"error": {
"message": "'tools' is not supported by this gateway yet (stateless slice — see docs).",
"type": "api_error",
"param": null,
"code": "not_implemented"
}
}The quoted name in message is the first field that was refused.
Response#
{
"id": "resp_2c058e36a9f2418398cebdcd",
"object": "response",
"created_at": 1767225600,
"status": "completed",
"model": "claude-sonnet-4-6@anthropic",
"output": [
{
"type": "message",
"id": "msg_2c058e36a9f2418398cebdcd",
"status": "completed",
"role": "assistant",
"content": [{ "type": "output_text", "text": "A gateway is a single entry point in front of several services.", "annotations": [] }]
}
],
"usage": {
"input_tokens": 21,
"input_tokens_details": { "cached_tokens": 0 },
"output_tokens": 14,
"output_tokens_details": { "reasoning_tokens": 0 },
"total_tokens": 35
},
"store": false,
"error": null,
"incomplete_details": null,
"instructions": "Answer in one sentence.",
"metadata": {},
"parallel_tool_calls": true,
"tool_choice": "auto",
"tools": []
}- A completed response holds exactly one
messageitem with oneoutput_textpart. The in-progress and failed objects of a stream have an emptyoutput. parallel_tool_calls,tool_choiceandtoolsare constants.instructionsisnullwhen you sent none, andmetadatais{}.
Streaming#
With "stream": true each event is event: <type> and data: {…}, and every payload carries a sequence_number that starts at 0. The events come in this order:
response.createdandresponse.in_progress, with the response object in progress.- When the model produces text:
response.output_item.added,response.content_part.added, then oneresponse.output_text.deltaper fragment. response.output_text.done,response.content_part.doneandresponse.output_item.done, which carry the full text.- One last event:
response.completed,response.incompleteorresponse.failed.
event: response.output_text.delta
data: {"type":"response.output_text.delta","item_id":"msg_…","output_index":0,"content_index":0,"delta":"A gateway","sequence_number":4}
event: response.output_text.done
data: {"type":"response.output_text.done","item_id":"msg_…","output_index":0,"content_index":0,"text":"A gateway is a single entry point.","sequence_number":7}When the model stops answering mid-reply, the text part is closed, and the stream ends with response.incomplete and incomplete_details.reason set to read_timeout. When the model returns nothing, or the servers cannot be reached, it ends with response.failed, and response.error.code is empty_response or upstream_error.
Errors#
Errors use the OpenAI shape, as in chat completions: 401 invalid_api_key, 403 permission_denied, 404 model_not_found, 400 for a bad body, 501 not_implemented, and 502 or 504 with empty_response, upstream_error or read_timeout. A 504 adds a partial object, the response as far as it got, and the header X-Inference-Incomplete: read_timeout. When every model of the chain fails, a refusal from a model provider keeps the provider's own status and the code upstream_error. A 401 or 403 here can therefore come from the model provider, for example a model server that rejects the gateway's own credentials, and not from your key: check the key with GET /api/v1/auth/verify.
GET/v1/responses/{id}#
Always 404, because nothing is stored:
{
"error": {
"message": "Response 'resp_x' was not stored: this gateway is stateless (store is not supported yet).",
"type": "invalid_request_error",
"param": null,
"code": "not_found_error"
}
}There is no other route for responses: no delete, no cancel and no input listing.
Data handling#
Like chat completions: nothing is stored as a conversation, the call is metered, and common identifiers in the text are masked before it goes to a model that is not on the operator's own infrastructure. See your data.