OpenAI JavaScript and TypeScript SDK
The official openai package works with FreeTheAI in Node.js, Deno, Bun, and edge runtimes. Only baseURL and the key change. Keep the key on a server: never ship it in browser code.
Install and configure
bash
npm install openai
export FTAI_KEY="ftai_your_key_here"ts
import OpenAI from 'openai'
const client = new OpenAI({
baseURL: 'https://api.freetheai.org/v1',
apiKey: process.env.FTAI_KEY ?? '',
})js
import OpenAI from 'openai'
const client = new OpenAI({
baseURL: 'https://api.freetheai.org/v1',
apiKey: process.env.FTAI_KEY,
})js
const OpenAI = require('openai')
const client = new OpenAI({
baseURL: 'https://api.freetheai.org/v1',
apiKey: process.env.FTAI_KEY,
})The SDK also reads OPENAI_BASE_URL and OPENAI_API_KEY from the environment.
Chat completion
ts
const reply = await client.chat.completions.create({
model: 'fta/kimi/k3',
messages: [{ role: 'user', content: 'Write a haiku about the sea.' }],
})
console.log(reply.choices[0].message.content)Streaming
ts
const stream = await client.chat.completions.create({
model: 'fta/zai/glm-5.3',
messages: [{ role: 'user', content: 'Tell me a short story.' }],
stream: true,
})
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '')
}Stream to a browser
A minimal server route that keeps the key on the server and streams plain text to the page (works in any runtime with the Fetch API, such as Next.js route handlers, Hono, or Deno):
ts
import OpenAI from 'openai'
const client = new OpenAI({ baseURL: 'https://api.freetheai.org/v1', apiKey: process.env.FTAI_KEY })
export async function POST(request: Request): Promise<Response> {
const { prompt } = (await request.json()) as { prompt: string }
const stream = await client.chat.completions.create({
model: 'fta/zai/glm-5.3',
messages: [{ role: 'user', content: prompt }],
stream: true,
})
const encoder = new TextEncoder()
const body = new ReadableStream<Uint8Array>({
async start(controller) {
for await (const chunk of stream) {
const text = chunk.choices[0]?.delta?.content
if (text) controller.enqueue(encoder.encode(text))
}
controller.close()
},
})
return new Response(body, { headers: { 'Content-Type': 'text/plain; charset=utf-8' } })
}Responses API
ts
const response = await client.responses.create({
model: 'fta/zai/glm-5.3',
input: 'Summarize the plot of Hamlet in two sentences.',
})
console.log(response.output_text)Tool calls
See Tool calls for a complete TypeScript loop.
Errors
ts
import OpenAI from 'openai'
try {
await client.chat.completions.create({
model: 'fta/zai/glm-5.3',
messages: [{ role: 'user', content: 'Hi' }],
})
} catch (err) {
if (err instanceof OpenAI.APIError) {
// err.status: 401, 403, 404, 429, 502, 503, ...
// err.error: FreeTheAI's error object; its message is safe to show to people
const message = (err.error as { message?: string } | undefined)?.message ?? err.message
console.error(err.status, message, err.headers?.get('x-error-id'))
} else {
throw err
}
}Every message and its fix: Errors.

