---
url: https://docs.freetheai.org/getting-started/quickstart.md
description: >-
  Make your first FreeTheAI request in a few minutes with curl, Python,
  JavaScript, or TypeScript, using the OpenAI SDK and a free model.
---

# Quickstart

Make your first request in a few minutes. You need a FreeTheAI account, an API key, and today's check-in; the code is the same OpenAI client code you already know, with a different base URL and key.

## Get a key and check in

These steps happen on [freetheai.org](https://freetheai.org), by you:

1. [Create a free account](/getting-started/account) and confirm your email.
2. Open **Dashboard > API keys** and create a key. It starts with `ftai_`, is 53 characters long, and is shown only once, so copy all of it.
3. Do today's [check-in](/getting-started/check-in). Free models stay unlocked until 00:00 UTC.

## Save the key in an environment variable

Keep the key out of your code. The examples on this site read it from `FTAI_KEY`.

::: code-group

```bash [macOS / Linux]
export FTAI_KEY="ftai_your_key_here"
```

```powershell [Windows PowerShell]
$env:FTAI_KEY = "ftai_your_key_here"
```

```bat [Windows cmd]
set FTAI_KEY=ftai_your_key_here
```

:::

To keep it across terminals, add the `export` line to your shell profile, or on Windows run `setx FTAI_KEY "ftai_your_key_here"` and open a new terminal.

## Send your first request

Pick a language. Every example sends one message to `fta/zai/glm-5.3` and prints the reply.

::: code-group

```bash [curl]
curl https://api.freetheai.org/v1/chat/completions \
  -H "Authorization: Bearer $FTAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "fta/zai/glm-5.3",
    "messages": [
      {"role": "user", "content": "Explain recursion in one paragraph."}
    ]
  }'
```

```python [Python]
# pip install openai
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.freetheai.org/v1",
    api_key=os.environ["FTAI_KEY"],
)

reply = client.chat.completions.create(
    model="fta/zai/glm-5.3",
    messages=[{"role": "user", "content": "Explain recursion in one paragraph."}],
)
print(reply.choices[0].message.content)
```

```js [JavaScript]
// npm install openai   (save as quickstart.mjs, run: node quickstart.mjs)
import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'https://api.freetheai.org/v1',
  apiKey: process.env.FTAI_KEY,
})

const reply = await client.chat.completions.create({
  model: 'fta/zai/glm-5.3',
  messages: [{ role: 'user', content: 'Explain recursion in one paragraph.' }],
})
console.log(reply.choices[0].message.content)
```

```ts [TypeScript]
// npm install openai   (run with: npx tsx quickstart.ts)
import OpenAI from 'openai'
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions'

const client = new OpenAI({
  baseURL: 'https://api.freetheai.org/v1',
  apiKey: process.env.FTAI_KEY ?? '',
})

const messages: ChatCompletionMessageParam[] = [
  { role: 'user', content: 'Explain recursion in one paragraph.' },
]

const reply = await client.chat.completions.create({
  model: 'fta/zai/glm-5.3',
  messages,
})
console.log(reply.choices[0].message.content ?? '')
```

:::

A successful reply looks like this (shortened):

```json
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "fta/zai/glm-5.3",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Recursion is when a function solves a problem by calling itself..." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 14, "completion_tokens": 96, "total_tokens": 110 }
}
```

## Stream the reply

For long replies, turn on streaming so words arrive as they are written. Very long replies without streaming can time out in some apps.

::: code-group

```python [Python]
stream = client.chat.completions.create(
    model="fta/zai/glm-5.3",
    messages=[{"role": "user", "content": "Write a short story about a lighthouse."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
```

```ts [TypeScript]
const stream = await client.chat.completions.create({
  model: 'fta/zai/glm-5.3',
  messages: [{ role: 'user', content: 'Write a short story about a lighthouse.' }],
  stream: true,
})
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? '')
}
```

:::

More on [streaming](/concepts/streaming).

## If something goes wrong

| What you see | What to do |
| --- | --- |
| `401` `unauthorized` | The key is missing or incomplete. Paste the whole `ftai_` key (53 characters). |
| `403` Daily check-in required | Do today's [check-in](/getting-started/check-in), then send the request again. |
| `404` model not found | Copy an exact ID from [freetheai.org/models](https://freetheai.org/models), including the `fta/` part. |
| `429` concurrency limit | A reply is still running. Free accounts run one request at a time. |
| `503` model busy | Retry in a minute or pick another model. Busy refusals do not count. |

Every message and its fix is on the [errors page](/errors).

## Next steps

* Want retries, fallback models, and typed errors built in? Use an [official SDK](/sdks/) for Python, JavaScript and TypeScript, or Go.
* Use a different model: [Models and IDs](/concepts/models).
* Give the model functions to call: [Tool calls](/concepts/tool-calls).
* Already using the Anthropic SDK or Claude Code? Point it at `https://api.freetheai.org`: [Anthropic SDK](/sdks/anthropic).
* Set up an app instead of writing code: [App guides](/guides/).
