Skip to content
View as Markdown

Official SDKs

FreeTheAI has official, open-source clients for Python, JavaScript and TypeScript, and Go. They speak the same OpenAI-compatible API as everything else on this site, and they know how the FreeTheAI API answers, so common situations need no code of your own:

  • Busy models wait for the server's Retry-After, or move straight to your fallback models.
  • One request at a time is learned on the first refusal; extra calls queue instead of failing.
  • Long replies are fetched as a stream and assembled, so they don't hit idle timeouts.
  • Cut-off streams raise StreamInterruptedError with the partial text, never a silently short answer.
  • The daily check-in and daily limit raise CheckinRequiredError and DailyLimitError right away, with the link or the reset time.
  • Mistyped model IDs come back with suggestions, and a missing fta/ prefix is added for you.
LanguagePackageSource and docs
Pythonfreetheai on PyPIGitHub, docs
JavaScript and TypeScriptfreetheai on npm (no dependencies; Node.js 18+, Bun, Deno)GitHub, docs
Gogithub.com/Free-The-Ai/freetheai-go (standard library only)GitHub, docs

Prefer the OpenAI or Anthropic SDKs you already use? They work too: see OpenAI Python, OpenAI JavaScript, and Anthropic.

Install ​

bash
pip install freetheai
bash
npm install freetheai
bash
go get github.com/Free-The-Ai/freetheai-go@latest

The official SDKs read your key from FREETHEAI_API_KEY (or take it as an option):

bash
export FREETHEAI_API_KEY="ftai_your_key_here"

First request ​

python
from freetheai import FreeTheAI

client = FreeTheAI()  # reads FREETHEAI_API_KEY; or FreeTheAI(api_key="ftai_...")

reply = client.chat.completions.create(
    model="fta/zai/glm-5.3",
    messages=[{"role": "user", "content": "Write a haiku about open models."}],
)
print(reply["choices"][0]["message"]["content"])
ts
import { FreeTheAI } from 'freetheai'

const client = new FreeTheAI() // reads FREETHEAI_API_KEY; or new FreeTheAI({ apiKey: 'ftai_...' })

const reply = await client.chat.completions.create({
  model: 'fta/zai/glm-5.3',
  messages: [{ role: 'user', content: 'Write a haiku about open models.' }],
})
console.log(reply.choices[0]?.message.content)
go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/Free-The-Ai/freetheai-go"
)

func main() {
	client, err := freetheai.NewClient() // reads FREETHEAI_API_KEY; or freetheai.WithAPIKey("ftai_...")
	if err != nil {
		log.Fatal(err)
	}
	reply, err := client.Chat.Completions.New(context.Background(), freetheai.ChatCompletionParams{
		Model:    "fta/zai/glm-5.3",
		Messages: []freetheai.Message{{Role: "user", Content: "Write a haiku about open models."}},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reply.Choices[0].Message.Content)
}

The Python client returns plain dictionaries in the Chat Completions shape.

Streaming ​

python
messages = [{"role": "user", "content": "Tell me a short story."}]
for text in client.chat.completions.stream_text(model="fta/kimi/k3", messages=messages):
    print(text, end="", flush=True)
ts
for await (const text of client.chat.completions.streamText({
  model: 'fta/kimi/k3',
  messages: [{ role: 'user', content: 'Tell me a short story.' }],
})) {
  process.stdout.write(text)
}
go
stream, err := client.Chat.Completions.NewStreaming(ctx, params)
if err != nil {
	log.Fatal(err)
}
defer stream.Close()
for stream.Next() {
	for _, choice := range stream.Current().Choices {
		fmt.Print(choice.Delta.Content)
	}
}
if err := stream.Err(); err != nil {
	log.Fatal(err)
}

Fallback models ​

Give the client models to try, in order, when the first one is busy, filtered, or down. The reply's model says which one answered.

python
client = FreeTheAI(fallback_models=["fta/zai/glm-5.3-flash", "fta/mmx/minimax-m3"])
ts
const client = new FreeTheAI({ fallbackModels: ['fta/zai/glm-5.3-flash', 'fta/mmx/minimax-m3'] })
go
client, err := freetheai.NewClient(freetheai.WithFallbackModels("fta/zai/glm-5.3-flash", "fta/mmx/minimax-m3"))
python
answer = client.answer("What changed in Python 3.14?")
print(answer["answer"], answer["sources"])

results = client.search("python 3.14 release notes", num_results=5)
ts
const answer = await client.answer({ query: 'What changed in Node.js 22?' })
console.log(answer.answer, answer.sources)

const results = await client.search({ query: 'node 22 release notes', num_results: 5 })

See Search and Answer for the response fields.

Errors ​

Each SDK raises a specific error class for each FreeTheAI error, with the error ID to quote when there is one:

ErrorWhen
AuthenticationError, IncompleteKeyError401: a missing, wrong, or partly pasted key
CheckinRequiredError403: no check-in today (has the check-in link)
EmailNotVerifiedError403: the email is not confirmed
ModelNotFoundError404: unknown model, with suggestions
ContentFilterError, ImagesNotSupportedError400: filtered, or images sent to a text-only model
RequestTooLargeError413: body over 8 MB
ConcurrencyLimitError429: a reply is still running
DailyLimitError429: today's free requests are used (has the reset time)
ProviderBudgetError429: a model family's daily budget is used
ModelBusyError503: the model is busy right now
StreamInterruptedErrorA stream broke (has the partial text and error ID)
python
from freetheai import FreeTheAI, CheckinRequiredError, DailyLimitError

client = FreeTheAI()
try:
    reply = client.chat.completions.create(
        model="fta/zai/glm-5.3",
        messages=[{"role": "user", "content": "Hi"}],
    )
except CheckinRequiredError as err:
    print("Check in first:", err.checkin_url)
except DailyLimitError as err:
    print("Out of free requests until", err.resets_at)

In Go, every error is a typed value, so errors.As works (for example *freetheai.CheckinRequiredError). Every message and its fix is on the errors page.

Cookbook ​

The FreeTheAI Cookbook has runnable examples for each SDK, the OpenAI clients, curl, streaming, tool calling, web search, LangChain, LlamaIndex, the Vercel AI SDK, retrieval over local files, and structured JSON output.

FreeTheAI documentation. Paid models and plans are coming soon; the free tier has daily limits.