OpenAI SDK (Node)
Drop-in. Point baseURL at odnoga with the /v1 suffix.
Setup
import OpenAI from 'openai';
export const ai = new OpenAI({
apiKey: process.env.AIROUTER_API_KEY!,
baseURL: `${process.env.AIROUTER_BASE_URL}/v1`,
defaultHeaders: {
'x-airouter-end-user': process.env.USER_ID ?? 'anonymous',
},
});
Per-request end user (preferred — defaultHeaders is global):
await ai.chat.completions.create(
{ model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'hi' }] },
{ headers: { 'x-airouter-end-user': userId } },
);
Read response headers
const res = await ai.chat.completions.create(
{ model: 'gpt-4o-mini', messages: [...] },
{ headers: { 'x-airouter-end-user': userId } },
).withResponse();
console.log(res.response.headers.get('x-airouter-request-id'));
console.log(res.response.headers.get('x-airouter-cost-usd'));
const completion = res.data;
Streaming
const stream = await ai.chat.completions.create({
model: 'gpt-4o-mini', stream: true,
messages: [{ role: 'user', content: 'count to 5' }],
}, { headers: { 'x-airouter-end-user': userId } });
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
}
Managed prompt (use body)
The OpenAI SDK doesn't know about prompt. Inject it via the raw body:
await ai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [],
// @ts-expect-error – odnoga extension
prompt: { slug: 'welcome-email', label: 'production', variables: { name: 'Ada' } },
}, { headers: { 'x-airouter-end-user': userId } });
For full type-safety + _meta, use @odnoga/node instead.