---
url: https://docs.freetheai.org/sdks/anthropic.md
description: >-
  Use the official Anthropic Python and TypeScript SDKs with FreeTheAI's
  Messages endpoint and free models like GLM 5.3 and Kimi K3, including
  streaming and tool use.
---

# Anthropic SDK

FreeTheAI answers the Anthropic Messages format for every free model, so the official Anthropic SDKs work with a different base URL, your FreeTheAI key, and an `fta/` model ID.

* Base URL: `https://api.freetheai.org` (without `/v1`; the SDK adds `/v1/messages`)
* Key: your `ftai_` key as the API key
* Model: an `fta/` ID such as `fta/zai/glm-5.3`. Claude model names do not work.

::: info Not Claude
These requests run on the model you name, not on Claude. Features that only exist in Claude models may not work.
:::

## Install and configure

::: code-group

```python [Python]
# pip install anthropic
import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.freetheai.org",
    api_key=os.environ["FTAI_KEY"],
)
```

```ts [TypeScript]
// npm install @anthropic-ai/sdk
import Anthropic from '@anthropic-ai/sdk'

const client = new Anthropic({
  baseURL: 'https://api.freetheai.org',
  apiKey: process.env.FTAI_KEY,
})
```

:::

The SDKs also read `ANTHROPIC_BASE_URL` and `ANTHROPIC_API_KEY` from the environment.

## Create a message

::: code-group

```python [Python]
message = client.messages.create(
    model="fta/zai/glm-5.3",
    max_tokens=1024,
    system="You are a helpful assistant.",
    messages=[{"role": "user", "content": "Explain DNS in three sentences."}],
)
for block in message.content:
    if block.type == "text":
        print(block.text)
```

```ts [TypeScript]
const message = await client.messages.create({
  model: 'fta/zai/glm-5.3',
  max_tokens: 1024,
  system: 'You are a helpful assistant.',
  messages: [{ role: 'user', content: 'Explain DNS in three sentences.' }],
})
for (const block of message.content) {
  if (block.type === 'text') console.log(block.text)
}
```

:::

## Streaming

::: code-group

```python [Python]
with client.messages.stream(
    model="fta/kimi/k3",
    max_tokens=2048,
    messages=[{"role": "user", "content": "Write a short poem about rain."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
```

```ts [TypeScript]
const stream = client.messages.stream({
  model: 'fta/kimi/k3',
  max_tokens: 2048,
  messages: [{ role: 'user', content: 'Write a short poem about rain.' }],
})
stream.on('text', (text) => process.stdout.write(text))
await stream.finalMessage()
```

:::

## Tool use {#tool-use}

```python
import json

tools = [{
    "name": "get_weather",
    "description": "Get the current weather for a city.",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]

messages = [{"role": "user", "content": "Is it cold in Reykjavik right now?"}]

while True:
    message = client.messages.create(
        model="fta/zai/glm-5.3", max_tokens=1024, tools=tools, messages=messages,
    )
    messages.append({"role": "assistant", "content": message.content})
    if message.stop_reason != "tool_use":
        print("".join(b.text for b in message.content if b.type == "text"))
        break
    results = []
    for block in message.content:
        if block.type == "tool_use":
            weather = {"city": block.input["city"], "temperature_c": -2}  # your lookup here
            results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": json.dumps(weather),
            })
    messages.append({"role": "user", "content": results})
```

## Errors

The SDK raises `anthropic.APIStatusError` subclasses (`AuthenticationError`, `PermissionDeniedError`, `NotFoundError`, `RateLimitError`, ...). FreeTheAI's error body is the same on every endpoint; see [Errors](/errors).

## Claude Code

Claude Code uses the same endpoint. See the [Claude Code guide](/guides/claude-code) for a tested `settings.json`.
