---
url: https://docs.freetheai.org/sdks.md
description: >-
  The official FreeTheAI SDKs for Python, JavaScript and TypeScript, and Go -
  install, first request, streaming, web search, fallback models, and typed
  errors.
---

# 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.

| Language | Package | Source and docs |
| --- | --- | --- |
| Python | [`freetheai`](https://pypi.org/project/freetheai/) on PyPI | [GitHub](https://github.com/Free-The-Ai/freetheai-python), [docs](https://free-the-ai.github.io/freetheai-python/) |
| JavaScript and TypeScript | [`freetheai`](https://www.npmjs.com/package/freetheai) on npm (no dependencies; Node.js 18+, Bun, Deno) | [GitHub](https://github.com/Free-The-Ai/freetheai-js), [docs](https://free-the-ai.github.io/freetheai-js/) |
| Go | `github.com/Free-The-Ai/freetheai-go` (standard library only) | [GitHub](https://github.com/Free-The-Ai/freetheai-go), [docs](https://free-the-ai.github.io/freetheai-go/) |

Prefer the OpenAI or Anthropic SDKs you already use? They work too: see [OpenAI Python](/sdks/openai-python), [OpenAI JavaScript](/sdks/openai-javascript), and [Anthropic](/sdks/anthropic).

## Install

::: code-group

```bash [Python]
pip install freetheai
```

```bash [JavaScript / TypeScript]
npm install freetheai
```

```bash [Go]
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

::: code-group

```python [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 [TypeScript]
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 [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

::: code-group

```python [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 [TypeScript]
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 [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.

::: code-group

```python [Python]
client = FreeTheAI(fallback_models=["fta/zai/glm-5.3-flash", "fta/mmx/minimax-m3"])
```

```ts [TypeScript]
const client = new FreeTheAI({ fallbackModels: ['fta/zai/glm-5.3-flash', 'fta/mmx/minimax-m3'] })
```

```go [Go]
client, err := freetheai.NewClient(freetheai.WithFallbackModels("fta/zai/glm-5.3-flash", "fta/mmx/minimax-m3"))
```

:::

## Web search

::: code-group

```python [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 [TypeScript]
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](/api/search) and [Answer](/api/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:

| Error | When |
| --- | --- |
| `AuthenticationError`, `IncompleteKeyError` | `401`: a missing, wrong, or partly pasted key |
| `CheckinRequiredError` | `403`: no check-in today (has the check-in link) |
| `EmailNotVerifiedError` | `403`: the email is not confirmed |
| `ModelNotFoundError` | `404`: unknown model, with suggestions |
| `ContentFilterError`, `ImagesNotSupportedError` | `400`: filtered, or images sent to a text-only model |
| `RequestTooLargeError` | `413`: body over 8 MB |
| `ConcurrencyLimitError` | `429`: a reply is still running |
| `DailyLimitError` | `429`: today's free requests are used (has the reset time) |
| `ProviderBudgetError` | `429`: a model family's daily budget is used |
| `ModelBusyError` | `503`: the model is busy right now |
| `StreamInterruptedError` | A 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](/errors).

## Cookbook

The [FreeTheAI Cookbook](https://github.com/Free-The-Ai/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.
