Documentation menu
OpenAI-Compatible API
Read the page as Markdown for LLMsThe STAIR OpenAI-compatible API lets any OpenAI client call a STAIR agent by name over HTTPS, with streaming and multi-turn sessions.
How the OpenAI-compatible API works in STAIR
STAIR exposes its agents through the same request and response format as the OpenAI Chat Completions API. An existing OpenAI SDK or tool works after you change two things: the base URL and the API key.
| Method | Path | What it returns |
|---|---|---|
POST |
/ee/v1/chat/completions |
A chat completion from the agent, as one JSON object or as a Server-Sent Events (SSE) stream. |
GET |
/ee/v1/models |
The agents you can call, in the OpenAI model list format. |
GET |
/ee/v1/models/{id} |
One agent, where {id} is the agent name. |
The base URL for an OpenAI SDK is https://<your STAIR host>/ee/v1. The examples on this page use https://stair.example.com.
Key rules:
modelis the agent name. The value is the Agent Name exactly as it appears in Agents, for exampleDemo · Support Triage. It is not the name of an LLM: the agent's own model, instructions, toolsets, skills and sub-agents are used.- Use the plain agent name. STAIR Chat shows agents with a connection prefix, such as
DEV.Demo · Support Triage. The prefix belongs to STAIR Chat only; do not send it inmodel. - Access follows the ACL.
GET /ee/v1/modelslists only the agents your key or SSO session may use, and a request to any other agent fails with403or404. - Only chat completions and models. There are no
/responsesor/filesendpoints. Files and images travel inline in the message as content parts.
How to authenticate API requests
Every request needs one of these headers:
| Header | Value |
|---|---|
Authorization |
Bearer aip_sk_… (a personal API key or a service account key), or Bearer <SSO access token> |
STAIR-API-KEY |
aip_sk_… |
A personal API key acts with the roles and permissions of the user who created it. A service account key acts as the service account, which needs Execute Access on the agent. See API Keys and Service Accounts for how to create both.
How to send a chat completion request
Send a POST request with the agent name in model and the conversation in messages:
curl https://stair.example.com/ee/v1/chat/completions \
-H "Authorization: Bearer $STAIR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Session-Id: helpdesk-ticket-4711" \
-d '{
"model": "Demo · Support Triage",
"messages": [
{"role": "user", "content": "I was charged twice for my Brightpath Cloud subscription this month."}
]
}'
The response is a standard chat.completion object. The answer is in choices[0].message.content, and token counts are in usage.
With the OpenAI Python SDK, set base_url and api_key:
from openai import OpenAI
client = OpenAI(
base_url="https://stair.example.com/ee/v1",
api_key="aip_sk_...", # sent as Authorization: Bearer
)
response = client.chat.completions.create(
model="Demo · Support Triage",
messages=[{"role": "user", "content": "How long is a password reset link valid?"}],
extra_headers={"X-Session-Id": "helpdesk-ticket-4711"},
)
print(response.choices[0].message.content)
To list the agents you can call:
curl https://stair.example.com/ee/v1/models \
-H "Authorization: Bearer $STAIR_API_KEY"
Each entry has id (the agent name, to use as model), description and, when the agent's model has a context window set, context_length.
How to stream a response
Set "stream": true to receive the answer as Server-Sent Events. Each event is a chat.completion.chunk in the OpenAI format, and the stream ends with data: [DONE]. Add "stream_options": {"include_usage": true} to receive one more chunk with the total token usage before [DONE].
curl -N https://stair.example.com/ee/v1/chat/completions \
-H "STAIR-API-KEY: $STAIR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Demo · Finance Analyst",
"messages": [{"role": "user", "content": "What is 5% annual interest on 12,000 EUR over 3 years?"}],
"stream": true,
"stream_options": {"include_usage": true}
}'
stream = client.chat.completions.create(
model="Demo · Finance Analyst",
messages=[{"role": "user", "content": "What is 5% annual interest on 12,000 EUR over 3 years?"}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\nTokens:", chunk.usage.total_tokens)
How to continue a conversation with X-Session-Id
Send the same X-Session-Id header value with every request of one conversation. Without the header, each request opens a new session. The response carries the session id in its X-Session-Id header, so a client that sent no header can read the generated id and reuse it.
As with any OpenAI-compatible API, send the previous turns in messages on every request. A session holds one request at a time: a second request with the same X-Session-Id while the first is still running is rejected.
Use one session id per conversation, for example a ticket number or a UUID. Do not share one id between unrelated users or conversations.
How to send files and images
Files and images go inline in messages, as content parts of a user message:
{
"model": "Demo · Support Triage",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "The customer attached this screenshot of the error."},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}
]
}]
}
- Images: a
image_urlpart with adata:URI (Base64) or anhttpsURL. - Documents: a
filepart withfile_data(Base64) andfilename. Whether the agent can read the document depends on the agent's model.
There is no upload endpoint and no file id to reference later. Send the file again in a later request if the agent needs it.
Chat completions request reference
| Field | Required | Description |
|---|---|---|
model |
Yes | The agent name, exactly as in Agents. |
messages |
Yes | The conversation, at least one message. Roles system, user, assistant; content is a string or a list of content parts (text, image_url, file). |
stream |
No | true returns an SSE stream. Default false. |
stream_options.include_usage |
No | With stream: true, adds a final chunk with token usage before [DONE]. |
temperature |
No | Accepted for OpenAI compatibility (between 0 and 2). Generation is controlled by the agent's model settings in STAIR. |
max_tokens |
No | Accepted for OpenAI compatibility (greater than 0). Generation is controlled by the agent's model settings in STAIR. |
top_p |
No | Accepted for OpenAI compatibility (between 0 and 1). Generation is controlled by the agent's model settings in STAIR. |
| Header | Required | Description |
|---|---|---|
Authorization or STAIR-API-KEY |
Yes | The API key or SSO token, see How to authenticate API requests. |
X-Session-Id |
No | The conversation's session id. Without it, every request opens a new session. |
Content-Type |
Yes, for POST |
application/json. |
Troubleshooting the OpenAI-compatible API
401 "Invalid access token"
The key is missing, mistyped, revoked or expired, or the Authorization header is not in the Bearer <key> format. Create a new key in Connections → Tokens or in Service Accounts and send it in Authorization: Bearer or STAIR-API-KEY.
403 or 404 "Model '…' not found or access denied"
The model value does not match an agent you may use, or the key's holder has no access to it. Check the spelling, including spaces and the · character, and remove a STAIR Chat prefix such as DEV.. Call GET /ee/v1/models to see the exact names. For a service account, ask an administrator to grant Execute Access on the agent.
Request rejected because the session is busy
A request with the same X-Session-Id is still running. Wait for the first answer, or use a different session id for parallel requests.
Every answer forgets the previous turn
The previous turns were not sent. Include the earlier user and assistant messages in messages, and send the same X-Session-Id on each request.
FAQ
What do I put in the model field?
Put the agent name exactly as it appears in Agents, for example Demo · Support Triage. STAIR runs that agent with its own model, instructions and tools.
Can I use the official OpenAI SDKs?
Yes. Set the base URL to https://<your STAIR host>/ee/v1 and the API key to an aip_sk_ key. Use the chat completions methods; the Responses and Files APIs are not available.
Does the API support streaming?
Yes. Set stream: true to receive Server-Sent Events in the OpenAI chunk format, and stream_options.include_usage: true to get token usage at the end of the stream.
How do I keep a multi-turn conversation together?
Send the same X-Session-Id header with every request and include the previous turns in messages. Without the header, each request starts a new session.
How do I send a file to an agent?
Put it inline in the user message as a content part: image_url with a Base64 data: URI for images, or file with Base64 file_data for documents. There is no separate upload endpoint.