POST /ai/v2/direct/responses, one step at a time.
Want the concepts first? Read the Direct Responses guide. For every parameter and response field, see the Direct Responses API reference.
Why Direct Responses? It sends your request straight to the
model you name, with one request and response shape across every provider, and it bills the model’s published rate. It takes the same request body as the guarded Responses endpoint. Choose Direct Responses when you want the provider’s model as-is and handle safety yourself, and guarded Responses when you want Gloo’s guardrails and values alignment built in. See Which endpoint should I use?Prerequisites
Before starting, make sure you have:- A Gloo AI Studio account
- Your API key from the API Keys page, exported as
GLOO_API_KEY - Authentication setup: complete the Authentication Tutorial first
- Python 3.9+ with
requests(pip install requests), or Node.js 18+ (for built-infetch)
What You’ll Build
A small command-line assistant, built up in five steps:- First request: send a prompt and read the typed
output[]array - Choose a model: list the catalog and pick a model ID
- Stream: print the answer as it is generated
- Multi-turn: keep a conversation going with
instructionsand history - Tool call: let the model call a function you define, then answer with its result
Step 1: Your First Request
Send amodel and an input. input can be a plain string or an array of {role, content} items.
Understanding the Response
The answer arrives as a typedoutput[] array. Plain text comes back as a message item whose content[] holds output_text parts:
reasoning item, a tool call as a function_call item (Step 5) and a generated image as an image_generation_call item. Walking output[] by type, as output_text does, keeps your code working whichever items come back.
Already using the OpenAI SDKs? Point the base URL at
https://platform.ai.gloo.com/ai/v2/direct and call responses.create. This tutorial uses plain HTTP so every field is visible.Step 2: Choose a Model
Direct Responses calls exactly the model you name, so themodel ID is your main choice. The live catalog is at GET /platform/v2/models, which needs no authentication. Each entry has an id to use as model, plus capability flags such as supports_tools, supports_streaming and supports_reasoning, a context_window (the context window: how much input the model can take), list pricing, and is_deprecated.
List the models that can stream and call tools, and aren’t being retired:
- Capabilities. Steps 3 and 5 need
supports_streamingandsupports_tools. Image input needs a vision-capable model (supports_vision). - Cost. You pay the model’s published rate per token, with nothing added on direct endpoints. See Pricing and token spend.
- Reasoning. Models with
supports_reasoningcan think before answering; setreasoning.effortto control how much. See Reasoning and the Models That Think lesson. - Deprecations. A deprecated model lists a
replacement_model. See Model Lifecycle.
gloo-anthropic-claude-sonnet-4.6 in one MODEL constant, so trying another model is a one-line change. The Supported Models page shows the same catalog as a table.
Step 3: Stream the Answer
Set"stream": true to stream the answer as Server-Sent Events. Each event is an event: line followed by a data: line with a JSON payload. Three event types carry what you need:
Other events (
response.output_item.added, response.content_part.done and so on) mark structure and can be ignored for plain text.
The final event’s shape depends on the model. For OpenAI models its fields sit under a response key; for other models they’re at the top level, without output[]. Read data.response when present and fall back to data, and build the answer from the deltas.
Step 4: Hold a Multi-Turn Conversation
Useinstructions for the system prompt and send the whole conversation in input on every request. Conversation state lives in your application: previous_response_id and conversation (server-side chaining) are not supported.
You can also send
output[] items back exactly as you received them, which is how tool calls work in the next step. On a reasoning model, a reasoning item you send back is not carried into the next request: each request is reasoned afresh from the conversation in input. See Reasoning across turns.Step 5: Let the Model Call a Function
Tool use lets the model ask your code for information it doesn’t have. The round trip has three parts:- Send
toolswith your request. The model answers with afunction_callitem naming the function and its JSONarguments. - Run the function yourself.
- Send the conversation again with the model’s
function_calland afunction_call_outputholding your result under the samecall_id. The model then answers as a normalmessage.
function_call item like this:
arguments is a JSON string written by the model, so treat it like any other untrusted input: run_tool parses it, picks out only the campus field it expects, and sends an error result back to the model instead of crashing when the arguments don’t fit. To make the model call a tool rather than answer directly, send "tool_choice": "required".
Step 6: Handle Errors
Direct Responses errors follow the direct endpoint error contract. Every error carries:- a short
messagethat is safe to show your users as is - a
developer_messageandretryableflag for you - an
X-Gloo-Error-Codeheader with a stable lowercase code to branch on, and anX-Request-Idto include when you contact support - a
Retry-Afterheader on errors where Gloo knows how long to wait
error for provider and platform failures and under detail for refusals such as authentication or content policy. Read whichever is present, and never parse the wording of message: it can change, the codes don’t.
create follows the retry rule for a request someone is waiting on: it retries only errors marked retryable and network failures with no response, at most twice, with waits of 2 seconds or less. When Retry-After asks for longer, such as the 30 seconds a 503 can ask for, it raises at once so you can show message instead of leaving the terminal silent. A Retry-After that isn’t a number of seconds falls back to backoff. For a batch job nobody is watching, raise the budget to 5 requests in total and the wait cap to 30 seconds.
The same rules apply to a stream that fails before any output: it returns a normal HTTP status and body. A stream that fails after output has started ends with response.failed, whose response.error carries the string code, message, retryable and developer_message. For retry ceilings and partial-output handling, see Handling Streaming Failures.
Complete Code
To run every step from one file, start with the imports and constants below, then paste in the functions you already wrote. Copy only the definitions, not each step’s example calls, and use Step 6’s retryingcreate in place of Step 5’s simpler one. Finish with main(), export GLOO_API_KEY, and run it.
Troubleshooting
401 with X-Gloo-Error-Code: authentication_error
: The API key is missing, invalid or expired. Check that GLOO_API_KEY is exported in the shell that runs the script, and that the header reads Authorization: Bearer <key>.
400 naming an unknown model
: The model ID isn’t in the catalog. Copy an id from GET /platform/v2/models (Step 2).
The answer stops early, or status is "incomplete"
: The response reached max_output_tokens. On a reasoning model the thinking counts toward that limit too. Raise max_output_tokens or lower reasoning.effort; see Set your output limit for reasoning models.
The streaming loop prints nothing
: Match on the event: line (or the payload’s type), and read text only from response.output_text.delta. Don’t wait for output[] on the final event: for non-OpenAI models, response.completed has no output[].
The model never returns a function_call
: Check that the tool uses the nested {"type": "function", "function": {...}} schema and that the model has supports_tools in the catalog. To require a call, send "tool_choice": "required".
400 mentioning function calling or tools
: The model takes no tools, for example a Gemini image model. Remove tools, or pick a model with supports_tools.
The second tool request fails or ignores the result
: The function_call and function_call_output items need the same call_id, the call_id from the model’s function_call item. output must be a string, so JSON.stringify / json.dumps your result.
A parameter seems to have no effect
: Some models don’t take every sampling parameter (for example temperature on some reasoning models). The request still succeeds, and the parameters that weren’t applied are listed in the response’s ignored_params.
Next Steps
Direct Responses guide
Reasoning summaries, vision, image generation and pricing
Direct Responses API reference
Every request parameter and response field
Handling Streaming Failures
Retry ceilings, continuation and partial-output UX
Grounded Responses tutorial
Answer from your own content with the same request shape
Guarded Responses tutorial
The same body with Gloo’s guardrails and values-alignment
Tool Use
Tool schemas, tool results and tool use on Completions V2

