Skip to content
Responses API

Responses API

New

POST /v1/responses takes instructions and a list of input items and returns a response object made of output items, in the OpenAI Responses format. Use it with the responses API of the OpenAI SDK and with tools built on it, such as Codex CLI. The endpoint keeps no state: send the whole conversation with every request.

POST https://api.shannon-ai.com/v1/responses

The smallest request is a model id and a text. The reply is not streamed unless you ask for it.

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.shannon-ai.com/v1",
)

response = client.responses.create(
    model="shannon-3",
    input="Say hello in one sentence.",
)

print(response.output_text)

The reply is a response object. Its output holds the reasoning, when the model reasoned, and the message:

200 JSON
{
  "id": "resp_5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
  "object": "response",
  "created_at": 1791625200,
  "model": "shannon-3",
  "status": "completed",
  "error": null,
  "incomplete_details": null,
  "instructions": null,
  "metadata": {},
  "parallel_tool_calls": true,
  "temperature": null,
  "tool_choice": "auto",
  "tools": [],
  "top_p": null,
  "output": [
    {
      "id": "rs_8a2e6c1f4b7d4e03b9c5a1d70f3e2b64",
      "type": "reasoning",
      "summary": [
        {
          "type": "summary_text",
          "text": "The user wants a greeting in one sentence. Keep it short and friendly."
        }
      ]
    },
    {
      "id": "msg_1c7b9e3a5d2f4a86b0e4c8d19a6f7e25",
      "type": "message",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "Hello, it is good to meet you.",
          "annotations": []
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 1184,
    "output_tokens": 46,
    "total_tokens": 1230
  }
}

Request fields

model and input are what a request needs. The Applied by column names the models on which a field changes the reply. The hosted open-weight models are the twelve ids of the model list; the Shannon 3 family is shannon-3, shannon-3-pro, shannon-3.1 and shannon-3.1-pro. Models & pricing

Field Type Default Description Applied by
model string Required. An id from the model list. Matching is not case-sensitive. A missing or unpublished id returns 400 unknown model. All models
input string | array A string, which is read as one user message, or an array of input items. See Input items below. All models
instructions string Instructions for the model, the system prompt of this format. Hosted open-weight models, shannon-1.6-*, shannon-2-*, shannon-coder-1
stream boolean false true sends the reply as server-sent events. See Streaming below. All models
max_output_tokens integer 4096 Upper limit of the reply, in tokens. A value outside 1 to 65,536 is moved into that range. It is also the amount set aside from your balance while the request runs. See Output limit below. Hosted open-weight models, shannon-1.6-*, shannon-2-*, shannon-coder-1
temperature number Sampling temperature. On the hosted open-weight models values are kept between 0 and 2. Hosted open-weight models; shannon-1.6-*, shannon-2-* and shannon-coder-1 on replies that are not streamed
top_p number Nucleus sampling. Values are kept between 0 and 1. Hosted open-weight models
tools array The functions the model may call, in the flat form of this format: {"type": "function", "name", "description", "parameters"}. See Tools below. All models
tool_choice string | object auto "auto" lets the model decide. "required" makes it call a tool. {"type": "function", "name": "…"} makes it call that tool. Hosted open-weight models
reasoning object {"effort": "…"} with off, low, medium or high. Any other value returns 400. Hosted open-weight models
text object {"format": {…}} asks for a JSON answer. See Structured output below. All Shannon tiers; hosted open-weight models as listed per id

previous_response_id, store, metadata, parallel_tool_calls, truncation, include, user and prompt_cache_key are accepted so that existing client code runs unchanged. They do not change the reply. Because no conversation is stored, a follow-up request carries the earlier turns in input.

Input items

An input item is either a message, with a role and a content, or a typed item that carries a tool call or its result. content is a string or an array of parts.

Item Description Applied by
{"role": "user", "content": …} What you ask. content is a string, or input_text and input_image parts. All models
{"role": "assistant", "content": …} An earlier reply of the model. content is a string, or output_text parts. All models
{"role": "system", "content": …}
{"role": "developer", "content": …}
Instructions inside the conversation. Hosted open-weight models
{"type": "function_call", "call_id": "…", "name": "…", "arguments": "…"} A tool call the model made in an earlier reply. arguments is a JSON string. All models
{"type": "function_call_output", "call_id": "…", "output": "…"} The result of that call. call_id is the id of the call and output the result as a string. All models

Put instructions in the instructions field. With a Shannon 3 family id, put instructions that must hold into the user message.

The items of a reply's output can go back into input as they are: message and function_call items are read, reasoning items are skipped.

Content parts

Part Description Available on
{"type": "input_text", "text": "…"} Text of a user message. All models
{"type": "output_text", "text": "…"} Text of an assistant message. All models
{"type": "input_image", "image_url": "…"} An image, as a data: URL with base64 content or as an http(s) URL. Shannon 3 family, shannon-1.6-lite, shannon-1.6-pro, and the hosted open-weight models that list image input
{"type": "input_file", "file_data": "data:application/pdf;base64,…"} A document (PDF, Word, PowerPoint or Excel): file_data holds a data: URL, or file_url an http(s) URL. Shannon 3 family

On the Shannon tiers images and files are read from the last user item of input. Sizes and limits have their own page. Images and files

A request with instructions and options

This request sends instructions, a conversation as input items, an output limit, a temperature and a reasoning effort. It uses a hosted open-weight model, which applies all of them.

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.shannon-ai.com/v1",
)

response = client.responses.create(
    model="DeepSeek-V4-Flash-0731-W4A16-AUTOROUND-REAP",
    instructions="You are a physics teacher. Answer in two sentences.",
    input=[
        {"role": "user", "content": "Why is the sky blue?"},
        {"role": "assistant", "content": "Air scatters blue light more than red light."},
        {"role": "user", "content": "And why are sunsets red?"},
    ],
    max_output_tokens=512,
    temperature=0.3,
    reasoning={"effort": "low"},
)

for item in response.output:
    if item.type == "reasoning":
        print("reasoning:", item.summary[0].text)
    elif item.type == "message":
        print("answer:", item.content[0].text)
print(response.usage)

The reply of a hosted open-weight model has id, object, model, created_at, status, output and usage. Its usage adds the tokens read from cache and the tokens spent on reasoning:

200 JSON
{
  "usage": {
    "input_tokens": 58,
    "input_tokens_details": {
      "cached_tokens": 0
    },
    "output_tokens": 67,
    "output_tokens_details": {
      "reasoning_tokens": 19
    },
    "total_tokens": 125
  }
}

The response object

id, object, status, output and usage are on every reply. Build your code on those.

Field Type Description Sent by
id string resp_ followed by 32 hexadecimal characters. All models
object string Always response. All models
status string completed. In a stream it is in_progress first, and failed in a response.failed event. All models
output array The output items in the order the model produced them: reasoning, message, function_call. All models
usage object input_tokens, output_tokens and total_tokens. All models
usage.input_tokens_details object cached_tokens: the input tokens read from the prompt cache. Hosted open-weight models
usage.output_tokens_details object reasoning_tokens: the output tokens spent on reasoning. Hosted open-weight models
model string The canonical id of the model that answered. Shannon 3 family, hosted open-weight models
created_at integer Time of the reply, in Unix seconds. Shannon 3 family, hosted open-weight models
instructions, tools, temperature, … instructions, tools and temperature repeat the request. error and incomplete_details are null, metadata is {}, parallel_tool_calls is true, tool_choice is auto and top_p is null. Shannon 3 family

Output items

Item Description
{"id": "rs_…", "type": "reasoning", "summary": [{"type": "summary_text", "text": "…"}]} The model's reasoning as one summary_text part. Present only when the model reasoned.
{"id": "msg_…", "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "…"}]} The answer: one output_text part with the text.
{"id": "fc_…", "type": "function_call", "call_id": "call_…", "name": "…", "arguments": "…"} A tool call. arguments is a JSON string. Send the result back with the same call_id.

The OpenAI SDKs join the text of the message for you in response.output_text.

Streaming

Set stream to true for server-sent events. Each frame has an event: line with the name of the event and a data: line with a JSON object; the object repeats the name in type. Match deltas to their item by output_index.

With the OpenAI SDK, read the events by their type:

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.shannon-ai.com/v1",
)

stream = client.responses.create(
    model="shannon-3",
    input="Explain server-sent events in three sentences.",
    stream=True,
)

for event in stream:
    kind = getattr(event, "type", "error")     # an event without a type is an error event
    if kind == "response.reasoning_summary_text.delta":
        pass                                   # a piece of reasoning: event.delta
    elif kind == "response.output_text.delta":
        print(event.delta, end="", flush=True)
    elif kind == "response.output_item.done" and event.item.type == "function_call":
        print("\ntool call:", event.item.name, event.item.arguments)
    elif kind == "response.completed":
        print("\n", event.response.usage)
    elif kind in ("response.failed", "error"):
        raise RuntimeError("the stream failed, send the request again")

The events arrive in this order. The groups for reasoning, the message and tool calls appear only when the reply has them.

Event Payload When
response.created response Always first. response.status is in_progress and response.output is empty.
response.in_progress response Always second, with the same object.
response.output_item.added output_index, item The reasoning starts: a reasoning item with an empty summary.
response.reasoning_summary_text.delta output_index, summary_index, delta A piece of the reasoning.
response.reasoning_summary_text.done output_index, summary_index, text The reasoning is complete: its whole text.
response.output_item.done output_index, item The finished reasoning item.
response.output_item.added output_index, item The answer starts: a message item with status in_progress and no content.
response.content_part.added output_index, content_index, part An empty output_text part opens.
response.output_text.delta output_index, content_index, delta A piece of the answer.
response.output_text.done output_index, content_index, text The answer is complete: its whole text.
response.content_part.done output_index, content_index, part The finished output_text part.
response.output_item.done output_index, item The finished message item, with status completed.
response.output_item.added output_index, item A tool call starts: a function_call item with call_id, name and empty arguments.
response.function_call_arguments.delta output_index, delta The arguments of the call, complete in one delta.
response.function_call_arguments.done output_index, arguments The same arguments, as arguments.
response.output_item.done output_index, item The finished function_call item.
response.completed response Always last on success: the whole response object with output and usage.
200 text/event-stream
event: response.created
data: {"type":"response.created","response":{"id":"resp_5f0c…","object":"response","status":"in_progress","output":[], …}}

event: response.in_progress
data: {"type":"response.in_progress","response":{"id":"resp_5f0c…","object":"response","status":"in_progress","output":[], …}}

event: response.output_item.added
data: {"type":"response.output_item.added","output_index":0,"item":{"id":"msg_1c7b…","type":"message","role":"assistant","status":"in_progress","content":[]}}

event: response.content_part.added
data: {"type":"response.content_part.added","output_index":0,"content_index":0,"part":{"type":"output_text","text":""}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","output_index":0,"content_index":0,"delta":"Server-sent"}

event: response.output_text.delta
data: {"type":"response.output_text.delta","output_index":0,"content_index":0,"delta":" events let a server push text over one HTTP reply."}

event: response.output_text.done
data: {"type":"response.output_text.done","output_index":0,"content_index":0,"text":"Server-sent events let a server push text over one HTTP reply."}

event: response.content_part.done
data: {"type":"response.content_part.done","output_index":0,"content_index":0,"part":{"type":"output_text","text":"Server-sent events let a server push text over one HTTP reply."}}

event: response.output_item.done
data: {"type":"response.output_item.done","output_index":0,"item":{"id":"msg_1c7b…","type":"message","role":"assistant","status":"completed","content":[{"type":"output_text","text":"Server-sent events let a server push text over one HTTP reply.","annotations":[]}]}}

event: response.completed
data: {"type":"response.completed","response":{"id":"resp_5f0c…","object":"response","status":"completed","output":[…],"usage":{"input_tokens":1190,"output_tokens":18,"total_tokens":1208}, …}}

A stream that fails

On the Shannon tiers a failed reply ends with response.failed in place of response.completed. Its response.status is failed and response.error holds a code, rate_limit_exceeded or server_error, and a message.

On the hosted open-weight models a failure is an error event with code api_error and a message. response.completed still follows it.

Treat a stream as failed when it holds a response.failed or an error event, and send the request again.

Tools

A tool is a function your code runs. Describe it in tools; when the model wants it, the reply holds a function_call item in place of, or next to, the message.

A tool definition in tools:

tools
[
  {
    "type": "function",
    "name": "get_weather",
    "description": "Current weather for a city.",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string"
        }
      },
      "required": [
        "city"
      ]
    }
  }
]

The output of a reply that calls it:

200 output
[
  {
    "id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
    "type": "function_call",
    "name": "get_weather",
    "call_id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
    "arguments": "{\"city\":\"Paris\"}"
  }
]

Run the function, then send the request again with the call and its result added to input:

input
[
  {
    "role": "user",
    "content": "What is the weather in Paris?"
  },
  {
    "type": "function_call",
    "call_id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
    "name": "get_weather",
    "arguments": "{\"city\":\"Paris\"}"
  },
  {
    "type": "function_call_output",
    "call_id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
    "output": "{\"temperature_c\": 18, \"sky\": \"cloudy\"}"
  }
]

Only tools of type function are read. On shannon-1.6-*, shannon-2-* and shannon-coder-1 the parameters schema is reduced to the common JSON Schema keywords: oneOf is read as anyOf, and keywords such as $ref, additionalProperties, const, default and title are not passed to the model.

tool_choice values required and a named function are applied by the hosted open-weight models.

The tool loop is described in full on its own page. Function Calling

Structured output

This format spells structured output as text.format. The schema sits directly in format, next to name and strict, not under a json_schema member as on Chat Completions.

  • {"type": "json_object"} asks for any JSON object.
  • {"type": "json_schema", "name", "schema", "strict"} asks for JSON that follows your schema. strict is true when you leave it out.
POST /v1/responses
{
  "model": "shannon-1.6-lite",
  "input": "Extract the city and the date: 'The conference opens in Lisbon on 12 May 2027.'",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "event",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "description": "ISO 8601 date"
          }
        },
        "required": [
          "city",
          "date"
        ]
      }
    }
  }
}

The JSON arrives as text in the output_text part of the message; parse it yourself. A hosted open-weight model without structured output returns 400.

output_text
{"city": "Lisbon", "date": "2027-05-12"}

Which model takes which form is listed on its own page. Structured Outputs

Reasoning

A model that reasons returns its reasoning as an output item of type reasoning, before the message. In a stream it arrives as response.reasoning_summary_text.delta events.

The hosted open-weight models apply reasoning.effort: off, low, medium or high, with high when you send nothing. off returns no reasoning item. Send it as an object; a bare string is not read on this endpoint.

The efforts are described on their own page. Reasoning effort

Output limit

max_output_tokens is 4,096 when you do not send it. It is the number of tokens set aside from your balance when the request starts; when the reply is complete, that amount is replaced by what the request used. A value that does not fit into your remaining balance returns 429 Quota exceeded.

It limits the length of the reply on shannon-1.6-*, shannon-2-* and shannon-coder-1, and the length of the answer text on the hosted open-weight models.

On this endpoint shannon-coder-1 is charged in tokens from your balance, like every other model.

A request body can be up to 32 MiB. Limits and balance

Errors

Errors use the OpenAI error body: an error object with type and message; some also carry code and param with the value null. The table lists what this endpoint returns most often. The full list, with what to retry, has its own page. Error Handling

Status Type Message When
401 authentication_error Missing authentication
Invalid API key
No API key was sent, or the key is unknown or revoked.
400 invalid_request_error unknown model: <id> model is missing or is not a published id.
400 invalid_request_error No user message provided. Shannon tiers: input holds no user text.
400 invalid_request_error <id> does not accept image input An image was sent to a hosted open-weight model without image input.
400 invalid_request_error <id> does not accept response_format text.format was sent to a hosted open-weight model without structured output.
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high reasoning.effort holds a value outside the list.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … The body is valid JSON but a field has the wrong type.
429 rate_limit_error Quota exceeded. Upgrade your plan at shannon-ai.com/plan max_output_tokens is larger than what is left of your balance.
429 rate_limit_error Too many requests. Retry in <n>s. Flood protection: more than 120 requests in one minute on your account.
500 api_error The model backend failed to answer. Please retry. The model did not produce a reply. Send the request again.
502 api_error The model backend failed to answer. Please retry. The same, on the hosted open-weight models.
504 api_error upstream timed out A hosted open-weight model took longer than the time limit of a reply that is not streamed. Send it with stream set to true.