Source: https://ailoot.ai/docs/nl-be/api/gemini/
Canonical: https://ailoot.ai/docs/nl-be/api/gemini/
Language: nl-be

[API](https://ailoot.ai/docs/nl-be/) 

# Gemini generateContent

[Markdown](https://ailoot.ai/docs/nl-be/api/gemini/index.md)

Het native Google Gemini-formaat: voor Gemini CLI, Google GenAI SDK en REST-clients.

POST`https://api.ailoot.ai/v1beta/models/{model}:generateContent`

Gemini generateContent

```bash
curl "https://api.ailoot.ai/v1beta/models/gemini-3.8-flash:generateContent" \
  -H "x-goog-api-key: $AILOOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {"role": "user", "parts": [{"text": "Bedenk drie namen voor een koffiebar."}]}
    ]
  }' 
```

```python
from google import genai
from google.genai import types
import os

client = genai.Client(
    api_key=os.environ["AILOOT_API_KEY"],
    http_options=types.HttpOptions(base_url="https://api.ailoot.ai"),  # zonder /v1beta
)

resp = client.models.generate_content(
    model="gemini-3.8-flash",
    contents="Bedenk drie namen voor een koffiebar.",
)
print(resp.text)
```

```js
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({
  apiKey: process.env.AILOOT_API_KEY,
  httpOptions: { baseUrl: "https://api.ailoot.ai" }, // zonder /v1beta
});

const resp = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: "Bedenk drie namen voor een koffiebar.",
});
console.log(resp.text);
```

200 OK

```json
{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [{ "text": "1. «Boon en stoom» 2. «De ochtendmaling» 3. «Koffiehuis op de hoek»" }]
      },
      "finishReason": "STOP"
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 9,
    "candidatesTokenCount": 27,
    "totalTokenCount": 36
  },
  "modelVersion": "gemini-3.8-flash"
}
```

## Authenticatie

| Parameter | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `x-goog-api-key` | header | verplicht | Sleutel `sk-…`. Ook deze headers werken: `Authorization: Bearer` of `x-api-key`. Voor compatibiliteit met Google wordt ook `?key=` in het adres geaccepteerd — met de laagste prioriteit; `?api_key=` wordt afgewezen met 400. We raden een header aan: zo komt de sleutel niet in de logs terecht. |

## Pad

| Parameter | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `model` | string | verplicht | Model-ID met het Gemini-formaat, bijvoorbeeld `gemini-3.8-flash` of `gemini-3.1-pro`. In totaal 27. |

POST`https://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=sse`

GET`https://api.ailoot.ai/v1beta/models`

## Verzoekbody

| Parameter | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `contents` | array | verplicht | Berichten met `role` (`user`/`model`) en `parts`: text, inlineData/fileData, functionCall/functionResponse. Alleen bijlagen die het model als invoer ondersteunt. |
| `systemInstruction` | object | optioneel | Systeeminstructie in tekstvorm: `{"parts": [{"text": "…"}]}`. |
| `generationConfig` | object | optioneel | `generationConfig` accepteert `temperature`, `topP`, `topK`, `maxOutputTokens`, `thinkingConfig`, `responseMimeType` (`text/plain` of `application/json`), `responseSchema` of `responseJsonSchema` (JSON-object), `stopSequences` (array van strings), `candidateCount: 1`, een geheel getal voor `seed`, numerieke waarden voor `presencePenalty` en `frequencyPenalty`. Toegestane bereiken en mogelijkheden hangen af van het specifieke model; kies voor een JSON-antwoord één ondersteunde schemavorm en `application/json`. Bij tekstmodellen is `responseModalities` uitsluitend `["TEXT"]`. |
| `safetySettings` | array | optioneel | Objecten met verplichte `category` en `threshold`, optionele `method`. Het specifieke model moet deze waarden ondersteunen. |
| `tools` | array | optioneel | Clientfuncties in `functionDeclarations` worden uitgevoerd door je applicatie. Bij tekstmodellen worden ook `{"googleSearch": {}}` en `{"urlContext": {}}` geaccepteerd: afzonderlijk of samen in de array `tools`. Noch Google Search noch URL context kan worden gecombineerd met `functionDeclarations` in hetzelfde verzoek. Voor afbeeldingen als output zijn alleen clientfuncties beschikbaar. Andere ingebouwde tools en explicit cache worden niet ondersteund. Search/URL context kunnen een reservering vereisen op basis van de volledige invoerlimiet; de daadwerkelijke `toolUsePromptTokenCount` worden als invoertokens geteld. |
| `toolConfig` | object | optioneel | `functionCallingConfig`: mode (AUTO/ANY/NONE/VALIDATED/MODE\_UNSPECIFIED), allowedFunctionNames. |

Als het model een veld, bijlage of combinatie van tools niet ondersteunt, wordt het verzoek vóór de reservering afgewezen — er wordt niets afgeschreven. Je ontvangt HTTP `400` met `status` `INVALID_ARGUMENT` en de klasse `invalid_request` (in `ErrorInfo.reason` — `INVALID_REQUEST`). Ongeldige JSON, fouten in padparameters en andere controles geven ook `400` terug; lees de foutmelding en de Request ID. De mogelijkheden hangen af van het model: controleer de formaten en invoertypen in de catalogus.

## PDF, audio, video en links

Voor Gemini-modellen die dit invoertype ondersteunen, geldt: `parts[].inlineData` bevat `mimeType` en niet-lege base64-data; een PDF moet een echt PDF-bestand zijn. `fileData` bevat een openbaar `https`-adres in `fileUri` en het MIME-type van het bestand. Voor YouTube mag je het MIME-type weglaten. `http`, niet-openbare adressen, `gs://` en Google Files API-objecten worden niet ondersteund; uploaden via Google Files API ook niet. Bij video kun je `videoMetadata`: `startOffset`/`endOffset` toevoegen als string in seconden (bijvoorbeeld `1.5s`) en `fps` moet groter dan 0 en maximaal 24 zijn. De bodygrootte, context, toegestane invoer en antwoordlimiet worden per model en formaat gecontroleerd.

| Invoer | Ondersteunde MIME-typen |
| --- | --- |
| Inline-afbeeldingen | image/png, image/jpeg, image/webp |
| Documenten | application/pdf; text/plain, text/html, text/css, text/csv, text/xml, text/rtf, text/markdown, text/javascript, application/x-javascript, text/x-python, application/x-python |
| Audio | audio/wav, audio/mp3, audio/mpeg, audio/aiff, audio/aac, audio/ogg, audio/flac |
| Video | video/mp4, video/mpeg, video/mov, video/quicktime, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp |

```python
import json, os, urllib.request

def generate(model, payload):
    req = urllib.request.Request(
        "https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
        data=json.dumps(payload).encode(),
        headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
                 "Content-Type": "application/json"},
    )
    # Eén keer versturen. Controleer na een time-out de Request ID in je gebruiksgeschiedenis voordat je opnieuw probeert.
    with urllib.request.urlopen(req, timeout=300) as response:
        print("Request ID:", response.headers.get("X-Request-ID"))
        return json.load(response)

import base64, pathlib, sys

# Geef een echt lokaal PDF-, audio- of videobestand op, met het ondersteunde MIME-type.
path, mime = pathlib.Path(sys.argv[1]), sys.argv[2]
payload = {"contents": [{"role": "user", "parts": [
    {"text": "Beschrijf kort de inhoud van het bestand."},
    {"inlineData": {"mimeType": mime,
                    "data": base64.b64encode(path.read_bytes()).decode()}},
]}]}
print(generate("gemini-3.8-flash", payload))
# Alternatieve bijlage: {"fileData": {"mimeType": mime, "fileUri": public_https_url}}
# Voor een echte YouTube-URL: {"fileData": {"fileUri": youtube_url}}
```

## Search en URL context

Clientfuncties in `functionDeclarations` worden uitgevoerd door je applicatie. Bij tekstmodellen worden ook `{"googleSearch": {}}` en `{"urlContext": {}}` geaccepteerd: afzonderlijk of samen in de array `tools`. Noch Google Search noch URL context kan worden gecombineerd met `functionDeclarations` in hetzelfde verzoek. Voor afbeeldingen als output zijn alleen clientfuncties beschikbaar. Andere ingebouwde tools en explicit cache worden niet ondersteund. Search/URL context kunnen een reservering vereisen op basis van de volledige invoerlimiet; de daadwerkelijke `toolUsePromptTokenCount` worden als invoertokens geteld.

```json
{"tools": [{"googleSearch": {}}, {"urlContext": {}}]}
```

## Afbeeldingen als output

Afbeeldingen in antwoorden in het Gemini-formaat worden alleen ondersteund door `gemini-3.1-flash-image`. Dit staat los van `/v1/images/generations`: andere afbeeldingsmodellen werken hier niet. Dit model accepteert maximaal 131072 invoertokens en 32768 antwoordtokens; de volledige kosten van het langst mogelijke antwoord worden vooraf gereserveerd.

`responseModalities` — een niet-lege verzameling TEXT/IMAGE zonder duplicaten. `imageConfig.imageSize`: 1K/2K/4K; `aspectRatio`: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:4, 4:1, 1:8, 8:1. Dit model accepteert tekst en inline PNG/JPEG/WebP als invoer; PDF/audio/video/fileData en ingebouwde Search/URL context worden hier niet geaccepteerd. Beschikbaarheid en prijzen voor jouw sleutel vind je in de catalogus en in `GET /v1/models`.

```python
import json, os, urllib.request

def generate(model, payload):
    req = urllib.request.Request(
        "https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
        data=json.dumps(payload).encode(),
        headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
                 "Content-Type": "application/json"},
    )
    # Eén keer versturen. Controleer na een time-out de Request ID in je gebruiksgeschiedenis voordat je opnieuw probeert.
    with urllib.request.urlopen(req, timeout=300) as response:
        print("Request ID:", response.headers.get("X-Request-ID"))
        return json.load(response)

import base64, pathlib

reply = generate("gemini-3.1-flash-image", {
    "contents": [{"role": "user", "parts": [{"text": "Aquarel: een vuurtoren bij zonsopgang"}]}],
    "generationConfig": {
        "responseModalities": ["TEXT", "IMAGE"],
        "imageConfig": {"aspectRatio": "1:1", "imageSize": "1K"},
    },
})
index = 0
for candidate in reply.get("candidates", []):
    for part in candidate.get("content", {}).get("parts", []):
        if "text" in part:
            print(part["text"])
        blob = part.get("inlineData", {})
        if blob.get("mimeType", "").startswith("image/") and blob.get("data"):
            index += 1
            extension = {"image/png": "png", "image/jpeg": "jpg",
                         "image/webp": "webp"}.get(blob["mimeType"], "bin")
            pathlib.Path(f"gemini-image-v{index}.{extension}").write_bytes(
                base64.b64decode(blob["data"]))
print("All returned images:", index)
```

## De volledige function calling-cyclus

De client voert de functies uit. Geef de volledige oorspronkelijke content van het model met thoughtSignature ongewijzigd terug, daarna functionResponse met dezelfde name en dezelfde id, als die id in functionCall aanwezig was.

```python
import json, os, urllib.request

def generate(model, payload):
    req = urllib.request.Request(
        "https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
        data=json.dumps(payload).encode(),
        headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
                 "Content-Type": "application/json"},
    )
    # Eén keer versturen. Controleer na een time-out de Request ID in je gebruiksgeschiedenis voordat je opnieuw probeert.
    with urllib.request.urlopen(req, timeout=300) as response:
        print("Request ID:", response.headers.get("X-Request-ID"))
        return json.load(response)

tools = [{"functionDeclarations": [{
    "name": "multiply", "description": "Twee getallen vermenigvuldigen",
    "parameters": {"type": "object", "properties": {
        "a": {"type": "number"}, "b": {"type": "number"}},
        "required": ["a", "b"]},
}]}]
contents = [{"role": "user", "parts": [{"text": "Vermenigvuldig 7 met 8 met behulp van de functie"}]}]
for turn in range(4):  # Beperk de toollus; verstuur een verzoek met een onduidelijk resultaat niet opnieuw.
    reply = generate("gemini-3.8-flash", {"contents": contents, "tools": tools})
    content = reply["candidates"][0]["content"]
    contents.append(content)  # Bewaar ALLE (ALL) oorspronkelijke onderdelen (parts) en thoughtSignature ongewijzigd.
    results = []
    for part in content.get("parts", []):
        call = part.get("functionCall")
        if not call:
            continue
        if call["name"] != "multiply":
            raise ValueError("Unexpected function")
        args = call["args"]
        result = {"name": call["name"], "response": {"value": args["a"] * args["b"]}}
        if "id" in call:
            result["id"] = call["id"]
        results.append({"functionResponse": result})
    if not results:
        print(content)
        break
    contents.append({"role": "user", "parts": results})
else:
    raise RuntimeError("Tool loop limit reached")
```

## Antwoord

| Parameter | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `candidates[].content.parts` | array |  | Antwoord van het model. |
| `usageMetadata` | object |  | `promptTokenCount`, `candidatesTokenCount`, `totalTokenCount`. |

Het betaalde Gemini-antwoord komt na de kostenberekening in zijn geheel binnen, niet woord voor woord. De Gemini-stream bevat geen statusregels — houd voldoende marge in de clienttimeout.

Nog vragen? Stuur de Request ID en een beschrijving — we helpen je verder.[Contact opnemen met support](mailto:support@ailoot.ai)

## Ailoot · Het bedrijf en zijn projectenportefeuille





Ailoot bouwt op opgebouwde operationele ervaring, een groot klantenbestand, een stabiele dienst en doorlopende KPI-controle.





Het bedrijf en zijn projectenportefeuille: miljoenen klanten; maandelijkse verkopen in de miljarden.





Ailoot gebruikt die operationele ervaring voor API-toegang tot AI-functies in klantproducten, agents, applicaties en automatiseringen.
