---
url: https://docs.freetheai.org/api/gemini.md
description: >-
  POST /v1beta/models/{model}:generateContent - the Gemini API format on
  FreeTheAI, for the Google Gen AI SDK and Gemini clients. Parameters, examples,
  streaming, and tool calls with free models.
---

# Gemini format

Generates content in the Gemini API format. The Google Gen AI SDKs and other Gemini clients use it. Every free model answers here, streamed or not, with function calling.

`POST https://api.freetheai.org/v1beta/models/{model}:generateContent`

`POST https://api.freetheai.org/v1beta/models/{model}:streamGenerateContent`

The model ID goes in the path, slashes and all: `/v1beta/models/fta/zai/glm-5.3:generateContent`. The Google Gen AI SDKs take the base URL **without** a version: `https://api.freetheai.org`. `/v1/models/{model}:generateContent` works too.

## Request

::: code-group

```bash [curl]
curl "https://api.freetheai.org/v1beta/models/fta/zai/glm-5.3:generateContent" \
  -H "x-goog-api-key: $FTAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "systemInstruction": {"parts": [{"text": "You are a concise assistant."}]},
    "contents": [{"role": "user", "parts": [{"text": "Give me a name for a grey cat."}]}],
    "generationConfig": {"maxOutputTokens": 512}
  }'
```

```python [Python]
# pip install google-genai
import os
from google import genai
from google.genai import types

client = genai.Client(
    api_key=os.environ["FTAI_KEY"],
    http_options=types.HttpOptions(base_url="https://api.freetheai.org"),
)

response = client.models.generate_content(
    model="fta/zai/glm-5.3",
    contents="Give me a name for a grey cat.",
    config=types.GenerateContentConfig(
        system_instruction="You are a concise assistant.",
        max_output_tokens=512,
    ),
)
print(response.text)
```

```ts [TypeScript]
// npm install @google/genai
import { GoogleGenAI } from '@google/genai'

const ai = new GoogleGenAI({
  apiKey: process.env.FTAI_KEY,
  httpOptions: { baseUrl: 'https://api.freetheai.org' },
})

const response = await ai.models.generateContent({
  model: 'fta/zai/glm-5.3',
  contents: 'Give me a name for a grey cat.',
  config: { systemInstruction: 'You are a concise assistant.', maxOutputTokens: 512 },
})
console.log(response.text)
```

:::

The key goes in the `x-goog-api-key` header (what the SDKs send) or a `?key=` query parameter. `Authorization: Bearer ftai_...` works too. A `?key=` is moved into the header before the request is logged.

## Body parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `contents` | array, **required** | Turns with a `role` of `user` or `model` and `parts`: `text`, `inlineData` images, `functionCall`, and `functionResponse`. |
| `systemInstruction` | object | The system prompt, as `{"parts": [{"text": ...}]}`. |
| `generationConfig` | object | `maxOutputTokens`, `temperature`, `topP`, `topK`, `stopSequences`, `responseMimeType` and `responseSchema` for JSON output, and `thinkingConfig`. |
| `tools` | array | `functionDeclarations` with `name`, `description`, and `parameters`. |
| `toolConfig` | object | `functionCallingConfig` with `mode` `AUTO`, `ANY`, or `NONE`, and `allowedFunctionNames`. |

`thinkingConfig` with `"thinkingBudget": 0` turns reasoning off for models that think; a budget or `includeThoughts` turns it on. Other Gemini fields are passed to the model when it supports them. Features that exist only in Gemini models may not work on other models.

## Response

```json
{
  "candidates": [
    {
      "content": { "role": "model", "parts": [{ "text": "How about Ash?" }] },
      "finishReason": "STOP",
      "index": 0
    }
  ],
  "usageMetadata": { "promptTokenCount": 24, "candidatesTokenCount": 6, "totalTokenCount": 30 },
  "modelVersion": "fta/zai/glm-5.3"
}
```

| Field | Description |
| --- | --- |
| `candidates[0].content.parts` | `text` parts, `functionCall` parts, and parts marked `"thought": true` for a model's reasoning. |
| `finishReason` | `STOP`, or `MAX_TOKENS` when the reply hit `maxOutputTokens`. |
| `usageMetadata` | `promptTokenCount`, `candidatesTokenCount` (reasoning not included), `thoughtsTokenCount` when the model reasoned, and `totalTokenCount`. |

## Streaming

`:streamGenerateContent` returns server-sent events, each a `GenerateContentResponse` with the next piece of text; usage arrives with the last one. `?alt=sse` is accepted. The SDK helpers work as usual:

```python
for chunk in client.models.generate_content_stream(
    model="fta/zai/glm-5.3",
    contents="Write a limerick about tea.",
):
    print(chunk.text or "", end="", flush=True)
```

A function call is sent once, whole, at the end of the stream.

## Models

Lists the models your key can use in Gemini's shape (`models/...` names). Any model ID from [`GET /v1/models`](/api/models) works in the path. `:countTokens` is not available.

## Errors

The same statuses as [Chat Completions](/api/chat-completions#errors), in FreeTheAI's error format. Every message: [Errors](/errors).
