OpenAI-compatible API
Chat Completions and Responses against the Asale gateway, with the official OpenAI SDKs. Change the base URL and the key; the rest of your code is untouched.
The OpenAI dialect is the broadest one the gateway speaks, and the one most third-party libraries already target. If your code uses the openai package — or anything that imitates it — this is the page you want.
Read the overview first for keys, models, billing and errors; everything here is the OpenAI-specific part.
Connection
| Base URL | https://gw.asale.ai/v1 |
| Auth header | Authorization: Bearer sk-asale-... |
| SDK env var | OPENAI_API_KEY, OPENAI_BASE_URL |
The /v1 belongs to the base URL here: OpenAI's clients append /chat/completions to whatever you give them.
Endpoints
| Method | Path | Notes |
|---|---|---|
| POST | /v1/chat/completions | The main one. |
| POST | /v1/responses | The Responses API. Codex ≥ 0.146 speaks only this. |
| POST | /v1/completions | Legacy text completions, mapped onto the same path. |
| GET | /v1/models | What the platform will match right now. |
Call it
curl https://gw.asale.ai/v1/chat/completions \
-H "Authorization: Bearer $ASALE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5",
"messages": [{"role": "user", "content": "Hello"}],
"stream": false
}'
# pip install openai
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ASALE_API_KEY"],
base_url="https://gw.asale.ai/v1",
)
resp = client.chat.completions.create(
model="gpt-5",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
// npm i openai
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.ASALE_API_KEY,
baseURL: "https://gw.asale.ai/v1",
});
const resp = await client.chat.completions.create({
model: "gpt-5",
messages: [{ role: "user", content: "Hello" }],
});
console.log(resp.choices[0].message.content);
Streaming
stream: true returns text/event-stream with chat.completion.chunk events and a final data: [DONE], exactly as the OpenAI API does. Your existing parser needs no changes.
stream = client.chat.completions.create(
model="gpt-5",
messages=[{"role": "user", "content": "Count to five"}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
Tool calling
tools and tool_choice pass through, and the assistant's tool_calls come back in the same shape. Send the result as a role: "tool" message with its tool_call_id, as usual.
The model behind a request may be served by a publisher on any supported vendor, and the gateway translates between wire formats. Provider-specific opaque blobs — a reasoning signature, an encrypted_content — are only handed back when the request and the server speak the same wire; otherwise they are dropped rather than forged.
Practical notes
- Set
max_tokens. It is what the balance hold is computed from. Leaving it out makes the hold conservative, which can read as "insufficient balance" on an account that has plenty for the actual reply. - Model names are the platform's.
GET /v1/modelsis the list; the market shows which of them have supply. - Images work where the model does. Request bodies are capped at 16 MiB, which is well above a typical inlined image; past that the gateway answers
413. nis ignored — one completion per request.