Guides
Use the OpenAI SDK
Point the official Python or TypeScript SDK at AlphaNeural, and reach threads, routing and traces from it.
The official OpenAI SDKs work against AlphaNeural unchanged: set the base URL and the key. Everything AlphaNeural adds is reachable through the SDKs' own escape hatches for extra headers and body fields.
Set up
# pip install openai
import os
from openai import OpenAI
client = OpenAI(
base_url="https://backend.alfnrl.io/v1",
api_key=os.environ["ALPHANEURAL_API_KEY"],
)
completion = client.chat.completions.create(
model="openrouter/openai/gpt-4o-mini",
messages=[{"role": "user", "content": "Hello"}],
)
print(completion.choices[0].message.content)// npm install openai
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://backend.alfnrl.io/v1",
apiKey: process.env.ALPHANEURAL_API_KEY,
});
const completion = await client.chat.completions.create({
model: "openrouter/openai/gpt-4o-mini",
messages: [{ role: "user", content: "Hello" }],
});
console.log(completion.choices[0].message.content);Get a key from the API Keys page, or create one on the Quickstart. client.models.list() works too, and each entry carries its price and context window as extra fields; see Models.
Keep a conversation
Read the thread id from the first response's X-Thread-Id header, then send it back as a header with each new message. See Threads and memory.
raw = client.chat.completions.with_raw_response.create(
model="openrouter/openai/gpt-4o-mini",
messages=[{"role": "user", "content": "My name is Ada."}],
)
thread_id = raw.headers["x-thread-id"]
first = raw.parse()
# Only the new message: the thread holds the rest.
second = client.chat.completions.create(
model="openrouter/anthropic/claude-haiku-4.5",
messages=[{"role": "user", "content": "What is my name?"}],
extra_headers={"X-Thread-Id": thread_id},
)const { data: first, response } = await client.chat.completions
.create({
model: "openrouter/openai/gpt-4o-mini",
messages: [{ role: "user", content: "My name is Ada." }],
})
.withResponse();
const threadId = response.headers.get("x-thread-id");
if (!threadId) throw new Error("expected an X-Thread-Id header");
// Only the new message: the thread holds the rest.
const second = await client.chat.completions.create(
{
model: "openrouter/anthropic/claude-haiku-4.5",
messages: [{ role: "user", content: "What is my name?" }],
},
{ headers: { "X-Thread-Id": threadId } },
);You can also choose the id yourself, a UUID for example, and send it from the first request: an id that does not exist yet starts a thread under that id.
Tag steps for a cost trace
The AlphaNeural body fields are not in the SDKs' types. Python sends them with extra_body; in TypeScript, spread them into the request from a separate object.
completion = client.chat.completions.create(
model="openrouter/openai/gpt-4o-mini",
messages=[{"role": "user", "content": "Summarise step one."}],
extra_body={"task_id": "invoice-run-914", "step_index": 0},
)// Not in the OpenAI types; the SDK sends whatever is in the body.
const traced = { task_id: "invoice-run-914", step_index: 0 };
const completion = await client.chat.completions.create({
model: "openrouter/openai/gpt-4o-mini",
messages: [{ role: "user", content: "Summarise step one." }],
...traced,
});Then read the trace with any HTTP client. See Cost traces.
Route with a spend ceiling
The simplest form is a model id: alphaneural/auto has the server pick the ladder, and needs nothing the SDK does not already send. Add max_spend through the same escape hatch to set your own ceiling. The escalation record comes back as an extra field on the completion.
completion = client.chat.completions.create(
model="alphaneural/auto",
messages=[{"role": "user", "content": "Summarise this in one line: ..."}],
max_tokens=200,
extra_body={"max_spend": 0.05},
)
receipt = completion.model_extra["escalation"]
print(receipt["model"], receipt["billed"])const ceiling = { max_spend: 0.05 };
const completion = await client.chat.completions.create({
model: "alphaneural/auto",
messages: [{ role: "user", content: "Summarise this in one line: ..." }],
max_tokens: 200,
...ceiling,
});
const { escalation } = completion as typeof completion & {
escalation: { model: string; billed: string };
};
console.log(escalation.model, escalation.billed);To write the ladder yourself, name a concrete model and send escalation.ladder, with a schema the answer must pass:
schema = {
"type": "object",
"required": ["invoice_number", "total"],
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
}
completion = client.chat.completions.create(
model="openrouter/openai/gpt-4o-mini",
messages=[{"role": "user", "content": "Invoice INV-0042, total 1,250.00 EUR. Reply in JSON."}],
response_format={"type": "json_object"},
extra_body={
"escalation": {
"ladder": [
"openrouter/openai/gpt-4o-mini",
"openrouter/anthropic/claude-haiku-4.5",
],
"verify": {"json_schema": schema},
},
"max_spend": 0.05,
},
)
escalation = completion.model_extra["escalation"]
print(escalation["model"], escalation["attempts"])const routing = {
escalation: {
ladder: ["openrouter/openai/gpt-4o-mini", "openrouter/anthropic/claude-haiku-4.5"],
verify: {
json_schema: {
type: "object",
required: ["invoice_number", "total"],
properties: {
invoice_number: { type: "string" },
total: { type: "number" },
},
},
},
},
max_spend: 0.05,
};
const completion = await client.chat.completions.create({
model: "openrouter/openai/gpt-4o-mini",
messages: [{ role: "user", content: "Invoice INV-0042, total 1,250.00 EUR. Reply in JSON." }],
response_format: { type: "json_object" },
...routing,
});
const { escalation } = completion as typeof completion & {
escalation: { model: string; attempts: unknown[] };
};
console.log(escalation.model, escalation.attempts);A 200 always carries an accepted answer. When no model's answer is accepted, the API answers 422, which the SDKs raise as UnprocessableEntityError; the body carries the same escalation record, with the reason in error.code:
import openai
try:
completion = client.chat.completions.create(
model="alphaneural/auto",
messages=[{"role": "user", "content": "Summarise this in one line: ..."}],
)
except openai.UnprocessableEntityError as e:
receipt = e.body["escalation"]
print(e.body["error"]["code"], receipt["attempts"])try {
await client.chat.completions.create({
model: "alphaneural/auto",
messages: [{ role: "user", content: "Summarise this in one line: ..." }],
});
} catch (err) {
if (err instanceof OpenAI.UnprocessableEntityError) {
// err.error is the body's `error` object: { message, type: "ladder_exhausted", code }.
console.error(err.error);
} else {
throw err;
}
}Your own ladder cannot stream; alphaneural/auto can, and sends the whole answer at once when the ladder is done. See Routing for the whole contract.
Handle a 402
The SDKs have no dedicated class for 402, so catch the general status error:
import openai
try:
client.chat.completions.create(
model="openrouter/openai/gpt-4o-mini",
messages=[{"role": "user", "content": "Hello"}],
)
except openai.APIStatusError as e:
if e.status_code == 402:
print("Balance is zero: add funds, then retry.")
else:
raisetry {
await client.chat.completions.create({
model: "openrouter/openai/gpt-4o-mini",
messages: [{ role: "user", content: "Hello" }],
});
} catch (err) {
if (err instanceof OpenAI.APIError && err.status === 402) {
console.error("Balance is zero: add funds, then retry.");
} else {
throw err;
}
}See Errors for every status the API returns.