# TokLab — full documentation and blog text > Call AI image, AI video, LLM and AI audio models with one TokLab key. Check the price before you send, get the same error codes from every model, and pay nothing for requests that fail. This file inlines every English documentation page and blog post. For live prices use each model's https://toklab.ai/models//llms.txt; the index is https://toklab.ai/llms.txt. # Documentation --- Source: https://toklab.ai/docs/api/agents An agent can use TokLab in three ways. They share the same API key, balance, models and limits, and they are billed the same. | Way | Best for | Setup | | --------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | [MCP server](https://toklab.ai/docs/api/mcp) | Claude Code, Cursor, Codex, VS Code and other MCP clients | Add `https://api.toklab.ai/v1/mcp` with your API key as a Bearer header | | Agent skill | Agents that load Agent Skills | The skill index is at [`/.well-known/agent-skills/index.json`](https://toklab.ai/.well-known/agent-skills/index.json) | | HTTP API | Your own code, or an agent writing code for you | [Quickstart](https://toklab.ai/docs/api/quickstart) | To run the agent itself on TokLab's text models instead, see [Coding agents on TokLab](https://toklab.ai/docs/api/coding-agents). ## Set your key once Create a key on the [API keys page](https://toklab.ai/apikeys) and export it, so the agent can read it without the key landing in your project files: ```bash export TOKLAB_API_KEY=YOUR_API_KEY ``` The API keys page also has a **Connect via MCP** button that prints a ready setup for each MCP client. ## What an agent does on TokLab 1. **Find a model**: `list_models` over MCP, or the model list in [`/llms.txt`](https://toklab.ai/llms.txt). Each model with a landing page has a plain-text summary at `https://toklab.ai/models//llms.txt` with its parameters, prices and examples. 2. **Read its input schema**: `get_model_schema` over MCP, or the model's documentation page. 3. **Use public media URLs**: generation endpoints accept reference images, videos and audio only as public `http(s)` URLs. Base64 input is rejected, so host local files somewhere reachable first. 4. **Check the price**: `get_pricing` over MCP returns the model's current rates in USD before anything is submitted. 5. **Submit and wait**: `submit_task`, then `get_task` with `wait_seconds: 50` until the task finishes. Over HTTP, submit to the model's endpoint and poll [`GET /v1/tasks/{id}`](https://toklab.ai/docs/api/tasks) about every three seconds. Failed tasks are not charged. A submission is not idempotent: retrying a request whose response you did not receive creates and charges a second task, so check your [Task logs](https://toklab.ai/tasks) or balance first. ## Limits to plan around | Limit | Default | Response when exceeded | | ------------------------------------------------------ | ------- | ------------------------ | | Image and video tasks in progress at once, per account | 50 | HTTP `429`, code `30002` | Requests can also be rate limited, which returns HTTP `429` as well. On HTTP `429`, wait for `Retry-After` when it is present; otherwise back off exponentially with jitter and a cap. Base the decision on the status code rather than parsing error bodies, because the text endpoints answer in the error format of their protocol. A batch job should keep a queue and submit new tasks as running ones finish, rather than sending everything at once. Contact [support@toklab.ai](mailto:support@toklab.ai) if you need a higher limit. ## Machine-readable entry points | URL | What it is | | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | [`/llms.txt`](https://toklab.ai/llms.txt) | Index of models, documentation and guides for language models | | `/models//llms.txt` | One model's parameters, prices and examples | | `/docs/.md` | Any documentation page as Markdown, for example [`/docs/api/overview.md`](https://toklab.ai/docs/api/overview.md) | | [`/.well-known/agent-skills/index.json`](https://toklab.ai/.well-known/agent-skills/index.json) | Agent skill index | | [`/.well-known/api-catalog`](https://toklab.ai/.well-known/api-catalog) | API catalog (RFC 9727) | | `https://api.toklab.ai/v1/mcp` | [MCP server](https://toklab.ai/docs/api/mcp) | --- Source: https://toklab.ai/docs/api/authentication ## Bearer authentication Send your key in the Authorization header on both submission and task queries: ```text Authorization: Bearer YOUR_API_KEY ``` Create and revoke keys in [API keys](https://toklab.ai/apikeys). A new key is displayed in full only when created; save it securely at that point. ## Keep keys server-side Read the key from an environment variable. Do not place it in browser code, public repositories, URLs, or screenshots. If a key is exposed, revoke it and create a replacement. ## Access to tasks Task queries require a key belonging to the account that created the task. Knowing a task ID does not grant access to its result. ## Authentication errors | Code | Action | | ------- | --------------------------------------------------- | | `10001` | Check that the key is present, correct, and active. | | `10002` | Check the key's access permissions. | See [Errors](https://toklab.ai/docs/api/errors) for the response shape. --- Source: https://toklab.ai/docs/api/balance ## Add credits Visit [Credits](https://toklab.ai/billing) to view your balance and add credits. TokLab uses one-time credit purchases; credits do not expire. ## Rates and usage Current model rates are available on the [models page](https://toklab.ai/models). GPT Image 2 is billed by token usage. Prompt length, reference images, quality, dimensions, and image count can affect the final charge. The Playground estimate is an estimate, not a fixed quote. View final charges in your account usage history. Public task responses do not include monetary fields. ## Insufficient balance Error code `30001` means there are not enough credits to run the request. Add credits before submitting again. Failed tasks are not charged. A connection timeout alone does not establish that a task failed; query the existing task ID to check its final state. ## View your history See [LLM logs](https://toklab.ai/usage) for charges and [Task logs](https://toklab.ai/tasks) for task history. --- Source: https://toklab.ai/docs/api/coding-agents Coding agents can use TokLab as their model provider. They send requests with your TokLab API key, and every request is billed by tokens to your TokLab balance instead of a subscription. | Agent | Endpoint it uses | Models | | ----------- | ------------------------------------------------------- | ------ | | Claude Code | Anthropic Messages, `https://api.toklab.ai/v1/messages` | Claude | | Codex CLI | OpenAI Responses, `https://api.toklab.ai/v1/responses` | GPT-6 | To let an agent *call* TokLab's image and video models instead, use the [MCP server](https://toklab.ai/docs/api/mcp) or see [Use TokLab from AI agents](https://toklab.ai/docs/api/agents). ## Claude Code Run this in the terminal you start Claude Code from: ```bash export ANTHROPIC_BASE_URL=https://api.toklab.ai export ANTHROPIC_API_KEY=YOUR_API_KEY export ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-5-5 export ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-5-5 export ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-haiku-5-5 claude --model claude-opus-5-5 ``` * **The base URL has no path.** Claude Code adds `/v1/messages` itself. * **The three `ANTHROPIC_DEFAULT_*_MODEL` variables** point Claude Code's `opus`, `sonnet` and `haiku` aliases, which it also uses for background work, at TokLab model IDs. You can also pass an ID directly, for example `claude --model claude-fable-5-1`. * **The key replaces your Claude plan.** In an interactive session, Claude Code asks you once to approve the key; from then on, requests are billed to your TokLab balance. Unset the variables to go back to your plan. To keep the settings for every launch, put the same variables in the `env` block of `~/.claude/settings.json`. That file then holds a key that spends your balance, so keep it private. | Model ID | Use it for | | ------------------- | --------------------------------------- | | `claude-opus-5-5` | Everyday coding | | `claude-fable-5-1` | Long refactors and hard debugging | | `claude-fable-5` | Setups that rely on forcing a tool call | | `claude-sonnet-5-5` | The `sonnet` alias | | `claude-haiku-5-5` | The `haiku` alias and background work | Live rates per million tokens are in the [model catalog](https://toklab.ai/models). ## Codex CLI Add TokLab to your user-level `~/.codex/config.toml`, keeping your other settings: ```toml model = "gpt-6-sol" model_provider = "toklab" [model_providers.toklab] name = "TokLab" base_url = "https://api.toklab.ai/v1" env_key = "TOKLAB_API_KEY" wire_api = "responses" ``` Then export your key and start Codex: ```bash export TOKLAB_API_KEY=YOUR_API_KEY codex ``` * **Use the user-level file.** Codex ignores `model_provider` and `model_providers` in a project's `.codex/config.toml`. * **Pick the model** with `model`, or for one session with `codex -m gpt-6-astra`. GPT-6 Astra suits the hardest tasks, GPT-6 Sol everyday coding and GPT-6 Luna fast, cheaper steps. * **The tested models are GPT-6.** Codex sends Responses requests; another text model needs to accept the Responses format, which its API reference lists, and has not been tested in Codex. ## Check the connection ```bash curl https://api.toklab.ai/v1/messages \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-haiku-5-5", "max_tokens": 32, "messages": [{"role": "user", "content": "Reply OK."}] }' ``` A working key returns a message with a short reply. For Codex, run `codex exec "Reply OK."` after setting up the configuration above. ## Cost and limits * Requests are billed by the tokens in each response. A coding session sends a long prompt prefix with every request: instructions, tool definitions and project files. Where the model supports prompt caching, later requests read that prefix from the cache at a lower rate. * Every request appears in your [LLM logs](https://toklab.ai/usage). Add credit on the [Credits](https://toklab.ai/billing) page. * HTTP `429` means too many requests at once. Run fewer parallel sessions or subagents, and wait for `Retry-After` when it is present. ## Troubleshooting | Symptom | Fix | | ---------------------- | ------------------------------------------------------------------------------------------------------------------ | | `401` | Check the key. For Claude Code, set either `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN`, not both. | | `404` on every request | Claude Code needs `ANTHROPIC_BASE_URL=https://api.toklab.ai`; Codex needs `base_url = "https://api.toklab.ai/v1"`. | | Model not available | Use a model ID listed above: Claude models for Claude Code, GPT-6 for Codex. | | Insufficient balance | Add credit on the [Credits](https://toklab.ai/billing) page. | | `429` | Fewer parallel sessions or subagents; respect `Retry-After` when present. | --- Source: https://toklab.ai/docs/api/errors ## How to read an error HTTP status describes the request to the API. `error.code` describes the reason for failure. They are separate fields: **HTTP 200 is not a business error code.** * A rejected submission returns an HTTP error status with an `error` object. * A successful task query returns HTTP 200. Read `status` to determine whether generation is `processing`, `completed`, or `failed`. * For a failed task, branch on `error.code`, not on the text in `message`. Different failure reasons have different codes; the same reason uses the same code across models. * `60002` is the fallback when a more specific public cause cannot be determined. Handle unrecognized future codes as a generic failure. {/* error-catalog:start */} ## Request errors These HTTP statuses describe a rejected or unconfirmed submission, or a failed task query. A submission timeout does not prove that no task was created. | Error code (`error.code`) | HTTP status | Meaning | Next step | | ------------------------- | ------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | `10001` | 401 | The API key is missing or invalid. | Check the Authorization header and API key. | | `10002` | 403 | You do not have permission to make this request. | Check access permissions. | | `20001` | 400, 413, 422 | The request was rejected. Check the parameters against the API documentation. | Correct the request parameters before retrying. | | `20002` | 400 | The requested model is not available. | Select a model listed in the model catalog. | | `30001` | 402 | Not enough credits to run this request. | Add credits before submitting. | | `30002` | 429 | Too many requests. Please wait and try again. | Wait and retry with backoff. Do not repeat accepted submissions. | | `50001` | 404 | Task not found. | Check the task ID and use the owning account’s key. | | `50002` | 503 | Submission could not be confirmed. Check your tasks before submitting again. | Check task history before submitting again; the request may have been accepted. | | `90001` | 503 | The service is temporarily unavailable. | Back off; retain any task ID already received. | ## Task failures A successful task query returns HTTP 200 even when generation failed. Check `status: "failed"` and `error.code` in the response. These codes describe the task outcome, not the HTTP request. Failed tasks are not charged. | Error code (`error.code`) | Meaning | Next step | | ------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------- | | `20001` | The request was rejected. Check the parameters against the API documentation. | Correct the request parameters before retrying. | | `50003` | The task did not complete within the allowed time. Please try again. | The task is not charged. You may submit a new task. | | `60001` | The request was rejected by the content policy. Please revise the prompt or input images. | Revise the prompt or media input. | | `60002` | Generation could not be completed. Please try again. | The task is not charged. You may submit a new task. | | `60003` | No output was generated. Please revise the prompt or try again. | Revise the input or submit a new task. | | `60004` | The generated output could not be delivered. Please try again. | The task is not charged. Try again later. | | `90001` | The service is temporarily unavailable. | Back off; retain any task ID already received. | {/* error-catalog:end */} ```json { "id": "task_...", "status": "failed", "error": { "code": 60002, "message": "Generation could not be completed. Please try again." } } ``` If submission itself times out, check your task history before submitting again: the first request may have been accepted. --- Source: https://toklab.ai/docs/api/mcp TokLab runs a remote [Model Context Protocol](https://modelcontextprotocol.io) server. An AI agent can use it to list image and video models, read their request schemas and prices, submit generation tasks and fetch the results, without you writing integration code. ```text https://api.toklab.ai/v1/mcp ``` * **Transport:** Streamable HTTP, stateless. The server supports protocol version `2026-07-28` and the earlier versions that start with an `initialize` handshake, back to `2024-11-05`. * **Authentication:** your TokLab API key as a Bearer token, `Authorization: Bearer YOUR_API_KEY`. Create one on the [API keys page](https://toklab.ai/apikeys); see [Authentication](https://toklab.ai/docs/api/authentication). * **Billing:** the same as the HTTP API. Every `submit_task` call is one request to the matching task endpoint and is charged in the same way. Clients that can only sign in with OAuth, with no field for a custom header, cannot connect yet. ## Connect a client The [API keys page](https://toklab.ai/apikeys) has a **Connect via MCP** button that fills in one of your keys for each client below. ### Claude Code ```bash claude mcp add --transport http toklab https://api.toklab.ai/v1/mcp \ --header "Authorization: Bearer YOUR_API_KEY" ``` ### Cursor Add to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` in a project: ```json { "mcpServers": { "toklab": { "url": "https://api.toklab.ai/v1/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` ### Codex CLI Codex reads the key from an environment variable: ```bash export TOKLAB_API_KEY=YOUR_API_KEY codex mcp add toklab --url https://api.toklab.ai/v1/mcp \ --bearer-token-env-var TOKLAB_API_KEY ``` Codex stores the variable name, not the key. Start Codex from a shell where `TOKLAB_API_KEY` is set, for example by exporting it in your shell profile. ### VS Code Add to `.vscode/mcp.json`: ```json { "servers": { "toklab": { "type": "http", "url": "https://api.toklab.ai/v1/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` Any other client that supports remote Streamable HTTP servers with a custom `Authorization` header is set up the same way. ## Tools | Tool | What it does | Charges your balance | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | | `list_models` | Lists the model IDs `submit_task` accepts, each with its documentation link. Optional `endpoint`: `images` or `videos`. | No | | `get_model_schema` | Returns the JSON Schema of a model's request body. Rules that JSON Schema cannot express, such as conditional requirements and cross-field limits, are enforced by the API and described on the model's documentation page. | No | | `get_pricing` | Returns a model's current list prices in USD, from the same live rates billing uses, including any [model tiers](https://toklab.ai/docs/api/model-tiers). | No | | `submit_task` | Submits one task: `model` plus `input`, the request body described by `get_model_schema`. Returns a task ID. | **Yes**, for every call that creates a task | | `get_task` | Returns a task's status and output. Optional `wait_seconds` (0–50) waits on the server while the task is still running. | No | | `get_balance` | Returns the remaining balance, in USD, of the account that owns the key. | No | `submit_task` is not idempotent. Retrying a call creates and charges a second task, so check `get_task`, `get_balance` or your [Task logs](https://toklab.ai/tasks) before retrying a call whose result you did not receive. ## Typical flow 1. `list_models` with `endpoint: "images"`. 2. `get_model_schema` for the model you picked. 3. Optionally, `get_pricing` to see the rate first. 4. `submit_task` with `model` and an `input` that matches the schema. 5. `get_task` with `wait_seconds: 50`, repeated while `status` is `processing`, then read `output`. Generation is asynchronous, exactly as in the HTTP API: `submit_task` returns as soon as the task is accepted. `wait_seconds` saves the agent from polling in a loop, but a long video can still need several `get_task` calls. If a status check fails for a temporary reason during the wait, such as a rate limit or a server error, `get_task` returns the last `processing` result instead of the error; call it again. ## Rules carried over from the HTTP API * Reference images, videos and audio must be public `http(s)` URLs. Base64 input is rejected. * When the HTTP API answers, its response body is the tool result unchanged, with the same [error codes](https://toklab.ai/docs/api/errors). Errors raised before a request reaches it, such as an unknown model or invalid tool arguments, come back as a plain error message. A rejected key on the MCP endpoint itself is an HTTP `401`. * Failed tasks are not charged. * An account can have up to 50 image and video tasks in progress at once by default. Further submissions return HTTP `429` with code `30002` until running tasks finish; see [Use TokLab from AI agents](https://toklab.ai/docs/api/agents). * Model IDs and parameters are the ones in each model's documentation. A model appears in `list_models` once it is live on the API. * Text models are not offered over MCP. Call them on the [text endpoints](https://toklab.ai/docs/api/overview), or run a coding agent on them as described in [Coding agents on TokLab](https://toklab.ai/docs/api/coding-agents). --- Source: https://toklab.ai/docs/api/model-tiers Some models are offered in more than one tier. A tier is the same model sold at a different price, for example a lower-cost tier next to the Default one. One API key reaches every tier; you choose a tier by the model name, not by a separate key or setting. ## Default tier The plain model name always uses the Default tier. Existing requests keep working unchanged when a model gains another tier. ```json { "model": "gpt-image-2" } ``` ## Choose a tier Append a colon and the tier ID to the model name: ```json { "model": "gpt-image-2:" } ``` This works for text, image, video and audio models, wherever the request names a model: the `model` field of a JSON body, the `model` form field of an audio upload, and the model segment of a Gemini native path. In a Gemini path the action stays last: ```text POST /v1beta/models/::generateContent ``` ## Find the tiers of a model * On each model page, a tier switch above the price table shows each tier's prices and the model ID to call. Pages with a single price list the tiers in a **Price tiers** table instead. Both appear only when the model has more than one tier. * Each model's Markdown guide, `/models//llms.txt`, lists the complete prices of every tier. * `GET /v1/models` lists `:` next to `` for every model that your key can call in more than one tier. In the Playground of text models, the tier selector switches between the same tiers. The Playground of image and video models has a price tier selector too when the model has more than one tier; its estimate follows the selected tier. The Playground of audio models uses the Default tier; call other tiers through the API. ## Billing and behavior * A tier request runs only in that tier and is billed at that tier's price. * If the tier cannot serve the request, the request fails. It never switches to another tier, so it is never billed at a different price. * Responses and task results report the plain model name. * A key that was created for one tier only can call that tier and no other. ## Errors | Code | Cause | | ------- | ------------------------------------------------------------------------------------------ | | `20002` | The tier does not exist, does not offer this model, or the endpoint does not accept tiers. | | `10002` | The key is not allowed to use the requested tier. | See [Errors](https://toklab.ai/docs/api/errors) for the response shape. --- Source: https://toklab.ai/docs/api/overview TokLab serves image, video, audio and text models through one API and one API key. Image, video and audio models run as asynchronous tasks: you submit a request, receive a task ID and poll for the result. Text models answer directly, in the request format of the model's vendor. ## Base URL ```text https://api.toklab.ai ``` Use HTTPS and send JSON request bodies. The audio endpoints take a `multipart/form-data` upload instead. ## Authentication Send your key as a Bearer token on every request, including task queries: ```text Authorization: Bearer YOUR_API_KEY ``` The Anthropic Messages endpoint also accepts the key in `x-api-key`, together with the `anthropic-version` header. See [Authentication](https://toklab.ai/docs/api/authentication). ## Media task endpoints | Method | Path | Purpose | | ------ | -------------------------- | --------------------------------------------------------------------------------------------------------------- | | POST | `/v1/images/generations` | Submit an image generation or editing task: GPT Image, Nano Banana and Midjourney. | | POST | `/v1/videos/generations` | Submit a video task: Seedance 2.5 and 2.0 (ModelArk request body), Veo 3.1, Kling 3.0, MiniMax H3 and SD Video. | | POST | `/v1/audio/transcriptions` | Submit an audio file for transcription with Whisper-1. | | POST | `/v1/audio/translations` | Submit an audio file for translation into English with Whisper-1. | | GET | `/v1/tasks/{id}` | Read the state and result of an image, video or audio task. | Reference images, videos and audio are passed as URLs in the request body. An image request becomes an edit when it includes input images. Each model's reference lists its parameters. ## Text endpoints | Method | Path | Request format | | ------ | ---------------------------------------------- | ------------------------- | | POST | `/v1/chat/completions` | OpenAI Chat Completions | | POST | `/v1/responses` | OpenAI Responses | | POST | `/v1/messages` | Anthropic Messages | | POST | `/v1beta/models/{model}:generateContent` | Google Gemini | | POST | `/v1beta/models/{model}:streamGenerateContent` | Google Gemini, streamed | | GET | `/v1/models` | List the available models | Not every text model supports every format. The model's API reference names the formats it accepts; for example, Claude Opus 5.5 accepts Chat Completions, Responses and Messages, while the Gemini text models use the `/v1beta` paths. ## Request lifecycle ### Media tasks 1. Submit the request. The response is a task, not the finished file: store its `id`. 2. Poll the task until it reaches a final state. Tasks on `/v1/tasks/{id}` report `processing`, then `completed` or `failed`. 3. Read the result. Images are in `output.data[].url`, videos in `output.video_url`, and Whisper output in `output.url`. Every result link points to TokLab's storage. On failure, inspect `error.code` and `error.message`. Failed tasks are not charged. There is no completion webhook; poll the task instead, as described in [Webhooks](https://toklab.ai/docs/api/webhooks). ### Text requests A text request returns the model's answer in the same response, in the vendor's official response shape. Set `stream` to `true`, or use `:streamGenerateContent` for Gemini, to receive server-sent events. Text models are billed per token. ## Next steps * [Quickstart](https://toklab.ai/docs/api/quickstart) * [Task states](https://toklab.ai/docs/api/tasks) * [Errors](https://toklab.ai/docs/api/errors) --- Source: https://toklab.ai/docs/api/quickstart ## Create an API key Sign in and create a key in [API keys](https://toklab.ai/apikeys). Save it when it is first shown. Add credits on the [Credits](https://toklab.ai/billing) page. Set `TOKLAB_API_KEY` in your server environment. Python examples require the `requests` package. ## Submit a task ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "An amber glass bottle on a cream background, studio lighting", "size": "1024x1024", "quality": "low" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gpt-image-2", "prompt": "An amber glass bottle on a cream background, studio lighting", "size": "1024x1024", "quality": "low", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-image-2', prompt: 'An amber glass bottle on a cream background, studio lighting', size: '1024x1024', quality: 'low', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gpt-image-2", "prompt": "An amber glass bottle on a cream background, studio lighting", "size": "1024x1024", "quality": "low" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Read the result Store the returned `id`, then query it with the same account's API key: ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Repeat every three seconds while the status is `processing`. When it is `completed`, read `output.data[].url`. If it is `failed`, inspect `error`. A polling timeout does not cancel generation. Save the task ID and resume querying it instead of submitting another generation request. See [Tasks](https://toklab.ai/docs/api/tasks) for a complete polling example. --- Source: https://toklab.ai/docs/api/tasks `GET /v1/tasks/{id}` returns every image, video and audio task, Seedance included. ## Task states | Status | Meaning | Next step | | ------------ | --------------------------------------------------- | ----------------------------------------- | | `processing` | The task has been accepted and is not yet finished. | Continue polling. | | `completed` | The task succeeded. | Read the result in `output`. | | `failed` | The task did not complete successfully. | Inspect `error`; the task is not charged. | ## Submission response Submission returns a task reference: ```json { "id": "task_...", "model": "gpt-image-2", "status": "processing", "created_at": 1789970508 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Poll at a modest interval, such as every three seconds, until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Complete polling example Run this after the Python submission example in the [Quickstart](https://toklab.ai/docs/api/quickstart). It uses the returned `task_id` and waits up to ten minutes. Reaching this local deadline stops polling only; retain the ID and resume querying the same task. ```python import time print(f"Task ID: {task_id}") deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task A completed task returns hosted image URLs and usage: ```json { "id": "task_...", "model": "gpt-image-2", "status": "completed", "created_at": 1789970508, "finished_at": 1789970538, "output": { "created": 1789970532, "data": [{"url": "https://static.toklab.ai/media/tasks/task_example/0.png"}], "usage": { "input_tokens": 29, "output_tokens": 196, "total_tokens": 225 } } } ``` | Field | Meaning | | --------------------------- | --------------------------------------------------------------------------------------------- | | `id` | Keep this ID for subsequent queries. | | `status` | `processing`, `completed`, or `failed`. | | `created_at`, `finished_at` | Unix timestamps in seconds; completion time is unset or zero while processing. | | `output.data[].url` | Generated image URLs, available on completion. | | `output.video_url` | The generated video URL, for video tasks. | | `output.url` | The output file URL, for Whisper-1 tasks. | | `output.usage` | Reported token usage, when available. Detail objects may contain text and image token counts. | | `error` | Structured error on a failed task. | This API uses asynchronous task delivery. It is not a synchronous Images SDK replacement; `stream` and `partial_images` are not supported. --- Source: https://toklab.ai/docs/api/webhooks ## Current availability The image, video and audio task APIs currently use polling. They do not provide a public completion webhook or accept a callback URL. ## Check for completion Use `GET /v1/tasks/{id}` with your API key and check every few seconds until `status` is `completed` or `failed`. If your application needs a notification, run this polling loop on your server and notify your own client when the task reaches a terminal state. Keep your API key on the server. See [Tasks](https://toklab.ai/docs/api/tasks) for response fields and a polling example. --- Source: https://toklab.ai/docs/claude-fable-5 Claude Fable 5 is Anthropic's previous Fable model, still available alongside Claude Fable 5.1. Send the official Anthropic Messages request to TokLab: change the base URL and the API key, keep the body. The same model also answers the OpenAI Chat Completions and Responses formats. ## Model ID | Model ID | Context window | Max output | Thinking | Default effort | | ---------------- | -------------- | ----------- | ------------------- | -------------- | | `claude-fable-5` | 1M tokens | 128K tokens | Adaptive, always on | `high` | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/messages \ -H "x-api-key: $TOKLAB_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-fable-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}] }' ``` ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai", ) message = client.messages.create( model="claude-fable-5", max_tokens=1024, messages=[{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}], ) print("".join(block.text for block in message.content if block.type == "text")) ``` ```javascript import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai", }); const message = await client.messages.create({ model: "claude-fable-5", max_tokens: 1024, messages: [{ role: "user", content: "Summarize the trade-offs of event sourcing in three bullet points." }], }); for (const block of message.content) if (block.type === "text") console.log(block.text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "claude-fable-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}]}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/messages", bytes.NewReader(body)) req.Header.Set("x-api-key", os.Getenv("TOKLAB_API_KEY")) req.Header.Set("anthropic-version", "2023-06-01") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | The Messages endpoint forwards your request body as sent, including optional fields, and returns the official response. An `anthropic-beta` header is passed on as well. Keep the API key in server-side code. ## Parameters | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------- | ------------------- | -------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `claude-fable-5`. | | `max_tokens` | integer | Yes | — | 0–128000. Includes the tokens spent on thinking. `0` only pre-warms the prompt cache. | | `messages` | object\[] | Yes | — | Alternating `user` and `assistant` turns; `content` is a string or an array of content blocks. The last turn must be `user`. Exception: to continue a `pause_turn` response, send its content back as the last `assistant` message. | | `system` | string or object\[] | No | — | System prompt. | | `thinking` | object | No | `{"type": "adaptive"}` | Thinking is adaptive and always on. `display`: `omitted` (default) or `summarized`. | | `output_config.effort` | enum | No | `high` | `low`, `medium`, `high`, `xhigh`, `max`. Steers how much the model thinks. | | `output_config.format` | object | No | — | A JSON schema for structured output. | | `stop_sequences` | string\[] | No | — | Stop when one of these strings is generated. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `temperature` | number | No | — | Only `1` (the default) is accepted, for backwards compatibility; any other value returns a 400 error. Leave it out. | | `top_p` | number | No | — | Only values from `0.99` to `1` are accepted, for backwards compatibility; any other value returns a 400 error. Leave it out. | | `top_k` | integer | No | — | Not accepted: any value returns a 400 error. Leave it out. | | `tools` | object\[] | No | — | Tool definitions. | | `tool_choice` | object | No | — | `auto`, `any`, `tool` or `none`. | | `metadata.user_id` | string | No | — | An opaque id for your end user, up to 512 characters. | | `cache_control` | object | No | — | Top-level prompt-cache breakpoint. | | `container`, `context_management`, `mcp_servers`, `diagnostics`, `service_tier`, `inference_geo`, `speed` | — | No | — | Forwarded as sent. | ## Thinking and effort Claude Fable 5 always uses adaptive thinking: the model decides how much to think, and `output_config.effort` steers it. Higher effort usually means more output tokens, a longer wait and a higher cost. With `thinking.display` set to `summarized`, the response includes `thinking` blocks you can show; with `omitted`, Claude Fable 5 still returns a `thinking` block, but its text is empty. Read the answer from the `text` blocks, not from the first block. Thinking tokens are billed as output tokens. ## Media inputs Images and PDFs go in a user turn's `content` as `image` and `document` blocks, with a `url` source or, as in the official API, a `base64` source: ```json {"role": "user", "content": [ {"type": "image", "source": {"type": "url", "url": "https://example.com/chart.png"}}, {"type": "text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable file of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including thinking, * prompt-cache reads, and * prompt-cache writes, with separate 5-minute and 1-hour rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official message object: ```json { "id": "msg_...", "type": "message", "role": "assistant", "model": "claude-fable-5", "content": [{"type": "text", "text": "..."}], "stop_reason": "end_turn", "usage": {"input_tokens": 18, "output_tokens": 4, "cache_read_input_tokens": 0, "cache_creation_input_tokens": 0} } ``` With `"stream": true` the response is a stream of the official events: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta` and `message_stop`. The final `message_delta` carries the output token count. ## OpenAI-compatible formats The same model answers the OpenAI formats, so existing OpenAI code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="claude-fable-5", messages=[{"role": "user", "content": "Hello"}], ) response = client.responses.create(model="claude-fable-5", input="Hello") ``` These requests are converted to the Messages format, so a field with no Messages counterpart has no effect. Their responses carry the official OpenAI fields and may include a few extra usage fields; read `usage.total_tokens` and the official fields. ## Errors Errors on `/v1/messages` use the Anthropic shape, `{"type": "error", "error": {"type": "...", "message": "..."}}`; the other formats use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with the default effort and raise it only for tasks that need more thinking; effort changes both quality and cost. * Set `max_tokens` high enough for the thinking as well as the answer: it is one budget for both. * Put long, reused context first and mark it with `cache_control` so later requests read it from the cache at the lower rate. ## Related * [Claude Fable 5 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/claude-fable-5.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/claude-fable-5.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/claude-fable-5-1 Claude Fable 5.1 is Anthropic's current Fable model for demanding reasoning and long-running agentic work. Send the official Anthropic Messages request to TokLab: change the base URL and the API key, keep the body. The same model also answers the OpenAI Chat Completions and Responses formats. ## Model ID | Model ID | Context window | Max output | Thinking | Default effort | | ------------------ | -------------- | ----------- | ------------------- | -------------- | | `claude-fable-5-1` | 1M tokens | 128K tokens | Adaptive, always on | `high` | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/messages \ -H "x-api-key: $TOKLAB_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-fable-5-1", "max_tokens": 1024, "messages": [{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}] }' ``` ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai", ) message = client.messages.create( model="claude-fable-5-1", max_tokens=1024, messages=[{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}], ) print("".join(block.text for block in message.content if block.type == "text")) ``` ```javascript import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai", }); const message = await client.messages.create({ model: "claude-fable-5-1", max_tokens: 1024, messages: [{ role: "user", content: "Summarize the trade-offs of event sourcing in three bullet points." }], }); for (const block of message.content) if (block.type === "text") console.log(block.text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "claude-fable-5-1", "max_tokens": 1024, "messages": [{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}]}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/messages", bytes.NewReader(body)) req.Header.Set("x-api-key", os.Getenv("TOKLAB_API_KEY")) req.Header.Set("anthropic-version", "2023-06-01") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | The Messages endpoint forwards your request body as sent, including optional fields, and returns the official response. An `anthropic-beta` header is passed on as well. Keep the API key in server-side code. ## Parameters | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------- | ------------------- | -------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `claude-fable-5-1`. | | `max_tokens` | integer | Yes | — | 0–128000. Includes the tokens spent on thinking. `0` only pre-warms the prompt cache. | | `messages` | object\[] | Yes | — | Alternating `user` and `assistant` turns; `content` is a string or an array of content blocks. The last turn must be `user`. Exception: to continue a `pause_turn` response, send its content back as the last `assistant` message. | | `system` | string or object\[] | No | — | System prompt. | | `thinking` | object | No | `{"type": "adaptive"}` | Thinking is adaptive and always on. `display`: `omitted` (default) or `summarized`. | | `output_config.effort` | enum | No | `high` | `low`, `medium`, `high`, `xhigh`, `max`. Steers how much the model thinks. | | `output_config.format` | object | No | — | A JSON schema for structured output. | | `stop_sequences` | string\[] | No | — | Stop when one of these strings is generated. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `temperature` | number | No | — | Only `1` (the default) is accepted, for backwards compatibility; any other value returns a 400 error. Leave it out. | | `top_p` | number | No | — | Only values from `0.99` to `1` are accepted, for backwards compatibility; any other value returns a 400 error. Leave it out. | | `top_k` | integer | No | — | Not accepted: any value returns a 400 error. Leave it out. | | `tools` | object\[] | No | — | Tool definitions. | | `tool_choice` | object | No | — | `auto` or `none`; forcing a tool (`any` or `tool`) is not supported by this model. | | `metadata.user_id` | string | No | — | An opaque id for your end user, up to 512 characters. | | `cache_control` | object | No | — | Top-level prompt-cache breakpoint. | | `container`, `context_management`, `mcp_servers`, `diagnostics`, `service_tier`, `inference_geo`, `speed` | — | No | — | Forwarded as sent. | ## Thinking and effort Claude Fable 5.1 always uses adaptive thinking: the model decides how much to think, and `output_config.effort` steers it. Higher effort usually means more output tokens, a longer wait and a higher cost. With `thinking.display` set to `summarized`, the response includes `thinking` blocks you can show; with `omitted`, they are left out. Thinking tokens are billed as output tokens. ## Media inputs Images and PDFs go in a user turn's `content` as `image` and `document` blocks, with a `url` source or, as in the official API, a `base64` source: ```json {"role": "user", "content": [ {"type": "image", "source": {"type": "url", "url": "https://example.com/chart.png"}}, {"type": "text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable file of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including thinking, * prompt-cache reads, and * prompt-cache writes, with separate 5-minute and 1-hour rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official message object: ```json { "id": "msg_...", "type": "message", "role": "assistant", "model": "claude-fable-5-1", "content": [{"type": "text", "text": "..."}], "stop_reason": "end_turn", "usage": {"input_tokens": 18, "output_tokens": 4, "cache_read_input_tokens": 0, "cache_creation_input_tokens": 0} } ``` With `"stream": true` the response is a stream of the official events: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta` and `message_stop`. The final `message_delta` carries the output token count. ## OpenAI-compatible formats The same model answers the OpenAI formats, so existing OpenAI code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="claude-fable-5-1", messages=[{"role": "user", "content": "Hello"}], ) response = client.responses.create(model="claude-fable-5-1", input="Hello") ``` These requests are converted to the Messages format, so a field with no Messages counterpart has no effect. Their responses carry the official OpenAI fields and may include a few extra usage fields; read `usage.total_tokens` and the official fields. ## Errors Errors on `/v1/messages` use the Anthropic shape, `{"type": "error", "error": {"type": "...", "message": "..."}}`; the other formats use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with the default effort and raise it only for tasks that need more thinking; effort changes both quality and cost. * Set `max_tokens` high enough for the thinking as well as the answer: it is one budget for both. * Put long, reused context first and mark it with `cache_control` so later requests read it from the cache at the lower rate. ## Related * [Claude Fable 5.1 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/claude-fable-5-1.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/claude-fable-5-1.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/claude-haiku-5-5 Use `claude-haiku-5-5` with `POST https://api.toklab.ai/v1/messages`. The model accepts text, images and documents and returns text or tool requests. The [pricing page](https://toklab.ai/pricing) shows current token rates. The contract below follows Anthropic's model-specific documentation, checked October 9, 2026. Official capability limits and end-to-end verification are separate: a field being accepted does not prove that its intended effect occurred. See the compatibility results below before using advanced options. ## Quick start ```bash curl https://api.toklab.ai/v1/messages \ -H "x-api-key: $TOKLAB_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-haiku-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Classify this request as billing, technical or account: I was charged twice. Return only the label."}] }' ``` ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai", ) message = client.messages.create( model="claude-haiku-5-5", max_tokens=1024, messages=[{"role": "user", "content": "Summarize the purpose of a database index."}], ) for block in message.content: if block.type == "text": print(block.text) ``` ```javascript import Anthropic from '@anthropic-ai/sdk'; const client = new Anthropic({ apiKey: process.env.TOKLAB_API_KEY, baseURL: 'https://api.toklab.ai', }); const message = await client.messages.create({ model: 'claude-haiku-5-5', max_tokens: 1024, messages: [{ role: 'user', content: 'Summarize the purpose of a database index.' }], }); for (const block of message.content) { if (block.type === 'text') console.log(block.text); } ``` Keep your API key on the server. Select response blocks by `type`; a response can begin with thinking or a tool call. ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "os" "time" ) func main() { body, err := json.Marshal(map[string]any{ "model": "claude-haiku-5-5", "max_tokens": 1024, "messages": []map[string]string{ {"role": "user", "content": "Summarize the purpose of a database index."}, }, }) if err != nil { panic(err) } req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/messages", bytes.NewReader(body)) if err != nil { panic(err) } req.Header.Set("x-api-key", os.Getenv("TOKLAB_API_KEY")) req.Header.Set("anthropic-version", "2023-06-01") req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 2 * time.Minute} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() data, err := io.ReadAll(res.Body) if err != nil { panic(err) } if res.StatusCode >= 400 { panic(fmt.Sprintf("HTTP %d: %s", res.StatusCode, data)) } fmt.Println(string(data)) } ``` ## Request parameters There are **25 top-level fields** in the native contract. Optional does not mean nullable: only the rows explicitly mentioning `null` accept it. Unknown fields and unsupported sampling fields are discarded before forwarding, following the text-model parameter policy. Invalid values of supported fields return an `invalid_request_error` before generation. | Field | Required | Contract | | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `model` | Yes | `claude-haiku-5-5`. | | `max_tokens` | Yes | Integer 0–128000, including thinking. No API default. | | `messages` | Yes | 1–100000 messages with a role and string or content-block array. See conversation rules below. | | `system` | No | String or array of text blocks. Not null. | | `thinking` | No | Adaptive by default, or disabled. No manual budget and no between-tools mode. | | `output_config` | No | Object with `effort`, `format` and optional beta `task_budget`. | | `stop_sequences` | No | Array of stopping strings. | | `stream` | No | Boolean; false by default. | | `temperature` | No | Omit. Discarded here; the official compatibility value is 1. | | `top_p` | No | Omit. Discarded here; the official compatibility value is 0.99. | | `top_k` | No | Unsupported and discarded. | | `tools` | No | Array of client tools or official server tool declarations. | | `tool_choice` | No | `auto`, `none`, `any`, or named `tool`. Forced tools are supported. | | `metadata` | No | Object; optional `user_id` is a string of at most 512 characters or null. | | `cache_control` | No | Null or `{"type":"ephemeral","ttl":"5m"}`; TTL also accepts `1h`. Default TTL is 5m. | | `container` | No | Null, container ID string, or object with optional ID and up to 20 skills. | | `context_management` | No | Null or an object containing official context edits; beta headers apply. | | `mcp_servers` | No | Array of at most 20 URL servers; requires a matching MCP beta header. | | `service_tier` | No | `auto` or `standard_only`. Haiku has no Priority Tier capacity. | | `inference_geo` | No | `global`, `us`, or null. Omission uses the account default; inspect reported usage before assuming a region. | | `diagnostics` | No | Null or object; `previous_message_id` is null or a string of at most 256 characters. | | `compaction` | No | Null or `{"type":"summarize","instructions":"..."}`. Instructions are optional, nullable and at most 16384 characters. | | `fallbacks` | No | Null or `default` with the corresponding beta. Haiku has no automatic fallback models; explicit lists are invalid. | | `fallback_credit_token` | No | Null, a token string, or `{token,mode}`. The API must verify eligibility and validity; do not assume any model is an eligible target. | | `speed` | No | `standard` or null. Fast mode is unsupported. | Sampling parameters and the fixed standard speed are omitted from the form. The model ID is fixed to this page. Use the JSON request preview to inspect the submitted body. ## Thinking and effort The default is adaptive thinking with **medium** effort and omitted thinking text. Effort accepts `low`, `medium`, `high`, `xhigh`, `max`, or null to use the default. ```json { "thinking": {"type": "adaptive", "display": "summarized"}, "output_config": {"effort": "medium"} } ``` To disable thinking, use `{"type":"disabled"}` with low, medium or high effort. Do not include `display` or `block_binding` in disabled mode. `enabled`, `budget_tokens`, `between_tools`, and disabled thinking at xhigh/max are invalid. Adaptive `display` accepts `omitted`, `summarized`, or null. The generic beta value `updates` requires `thinking-display-updates-2026-08-18`; Anthropic does not currently establish readable progress updates for Haiku, so do not depend on that output. Optional `thinking.block_binding` requires `thinking-binding-controls-2026-08-01`. It is null or an object whose `prefix_mismatch_behavior` is `error`, `drop_block`, or null. Keep earlier conversation turns and complete thinking blocks unchanged when replaying history. Thinking signatures are bound to the account that produced them or an account linked to it. `output_config.task_budget` is null or `{ "type": "tokens", "total": 20000 }` with optional integer/null `remaining`. It requires `task-budgets-2026-03-13`; `total` must be at least 20000. No additional `remaining` range is imposed here. ## Tools and structured output Client tools require a name of 1–128 letters, digits, underscores or hyphens, and an `input_schema` with `type: "object"`. Use `tool_choice: {"type":"any"}` or `{"type":"tool","name":"lookup"}` to force a declared tool. With adaptive thinking, a forced tool response begins at the tool call without a thinking block. `disable_parallel_tool_use` is an optional boolean for auto, any and tool choices; it is not a field of none. Send the tool result back with the original `tool_use_id`. ```json { "tools": [{ "name": "lookup", "description": "Look up a product by SKU.", "input_schema": { "type": "object", "properties": {"sku": {"type": "string"}}, "required": ["sku"], "additionalProperties": false } }], "tool_choice": {"type": "tool", "name": "lookup"} } ``` Structured responses use `output_config.format: {"type":"json_schema","schema":{...}}`. Follow Anthropic's supported JSON Schema subset, including `additionalProperties: false` on objects. A valid shape does not guarantee factually correct values. Strict tools and structured output have schema-wide limits; see the [official structured-output reference](https://platform.claude.com/docs/en/build-with-claude/structured-outputs). Computer use requires `computer_toolset_20260801`; the old computer tool versions are invalid. Browser use has its own `browser_toolset_20260801`. Declaring a tool does not verify that a complete server-tool session works. Review the tool's official guide and any beta requirements before using it. ## Conversations and context management Ordinary assistant prefill is unsupported. A paused server-tool continuation is different: resend the complete assistant blocks as directed by the Messages protocol. A content-bearing system message can appear after a user message or paused server-tool result. It must be followed by an assistant message or be the last message. Consecutive system messages are evaluated as one group. Do not insert one between a client tool call and its required result. An empty-content system message may change only `output_config.effort` with `mid-conversation-output-config-2026-07-01`. It can appear anywhere. While thinking is disabled, it cannot change the effective effort. System `clear_at` accepts `never`, `next_user_message`, or null with `mid-conversation-system-clear-at-2026-08-21`; turn-scoped messages allow text only, without output config or block caching. Context edits include: | Edit | Beta | Main constraints | | -------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------- | | `clear_tool_uses_20250919` | `context-management-2025-06-27` | Trigger count at least 1; keep count at least 0. | | `clear_thinking_20251015` | `context-management-2025-06-27` | Keep all, or at least one thinking turn. Place before tool-use clearing when combining edits. | | `compact_20260112` | `compact-2026-01-12` | Input-token trigger at least 50000; default 150000. | On-demand `compaction` requires `compact-2026-09-04`. It cannot be combined with `context_management`, `stop_sequences`, an output format, forced tools or `task_budget.remaining`. A signed compaction block also cannot be combined with `task_budget.remaining` or threshold compaction. Preserve the returned block and signature when continuing. ## Images, PDFs and request size Images accept JPEG, PNG, GIF and WebP by URL, base64, or file reference. PDFs accept URL, base64 or file reference. File references require the relevant Files API beta and valid file access. Text documents can use text or content sources. The native request limit is 32 MB. Official image limits are up to 600 images, 10 MB of base64-encoded data per image and 8000 pixels on either edge; requests with many images can have tighter platform-specific limits. PDFs must be unencrypted and have at most 600 pages for this model's context size. The API remains responsible for inspecting remote files; local shape checks cannot prove the contents of a URL. Conversation JSON also supports native media content blocks. Full media-size and context-window boundary probes are separate from a small example request. ## Prompt caching and billing Haiku's minimum cacheable prompt is 512 tokens. Smaller marked prompts can run without creating a cache entry. Use at most four cache breakpoints; automatic top-level cache control consumes one slot. Put longer-lived cache prefixes before shorter-lived ones. `max_tokens: 0` requests cache prewarming without answer generation. It cannot accompany `stream: true`, structured output or forced tool use. Keep thinking and effort settings consistent between cache preparation and the requests that reuse it. Read `usage.input_tokens`, `output_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens`, and the 5m/1h breakdown under `cache_creation`. Thinking is included in output tokens; a reported thinking-token breakdown is not an extra charge to add again. Current rates are on the [pricing page](https://toklab.ai/pricing). ## Responses, streaming and errors A completed response contains `id`, `type: "message"`, `role: "assistant"`, `model`, `content`, `stop_reason`, `stop_sequence` and `usage`. Optional `container`, `diagnostics`, `context_management`, `stop_details` and `input_transformations` are preserved when returned. Handle `end_turn`, `max_tokens`, `stop_sequence`, `tool_use`, `pause_turn`, `compaction`, `refusal` and `model_context_window_exceeded`. A limit stop or refusal is not the same as an HTTP error. Never treat the first content block as guaranteed text. Streaming uses the Messages SSE events: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta` and `message_stop`. Also handle `ping` and `error` events. Preserve thinking signatures and tool blocks needed by later turns. Errors use the Anthropic shape: ```json {"type":"error","error":{"type":"invalid_request_error","message":"max_tokens must be an integer from 0 to 128000."}} ``` Requests that return an error are not charged. See [error handling](https://toklab.ai/docs/api/errors) for shared error types. ## OpenAI-compatible formats The same ID is available with `/v1/chat/completions` and `/v1/responses`. Use their native fields: Chat uses `messages`; Responses uses `input`. Native Claude options belong to Messages and should not be copied wholesale into an OpenAI-format body. ```bash curl https://api.toklab.ai/v1/chat/completions \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"claude-haiku-5-5","max_tokens":256,"messages":[{"role":"user","content":"Reply with OK."}]}' ``` ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"claude-haiku-5-5","max_output_tokens":256,"input":"Reply with OK."}' ``` ## Compatibility results Checked October 9, 2026 in the development environment. These checks establish the observed behavior of specific requests, not every official limit or production deployment. | Capability | Observed result | | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Native Messages and SSE | Text response and complete event sequence verified. | | Classification | Returned `Billing`; 41 input and 5 output tokens. | | Structured JSON and client tools | JSON values, automatic/none/named/any selection, strict-tool arguments and tool-result continuation verified. | | Images and PDFs | Returned the expected image color and PDF marker from base64 fixtures. Full media boundaries were not tested. | | Cache prewarming | `max_tokens: 0` returned no generated text and zero output tokens. | | Five-minute and one-hour caching | Creation and subsequent cache-hit usage verified for both TTLs. | | Stop sequences | Returned the requested stop reason and stopped before the excluded suffix. | | Thinking and effort | All five effort values were accepted. Some explicit disabled-thinking requests still returned thinking blocks. Acceptance alone does not verify effort behavior. | | System instructions and per-message effort | Results were inconsistent; a larger-budget per-message test still returned unrelated text. Test your exact conversation before rollout. | | On-demand compaction | Returned a signed compaction block and `stop_reason: compaction`. Complete replay and billing validation remain outstanding. | | Metadata and inference geography | `metadata.user_id` returned a permission error; explicit geography returned an account-type restriction. | | MCP | The current MCP beta returned a credential restriction. A complete MCP session was not verified. | | OpenAI Chat and Responses | Basic requests and explicit `max`/`none` reasoning requests returned the expected answer. Reasoning semantics were not independently established. | | Other beta fields | Task budget, binding controls and fallback `default` were accepted; full feature semantics were not established. | One-hour cache-write and compaction billing have not passed release validation. Maximum-context/output runs, hosted tools with separate charges, Files API access and fallback-credit redemption were not tested. Keep the official request shapes; do not infer support from a successful status alone. ## References * [Haiku 5.5 model overview](https://platform.claude.com/docs/en/models/haiku-5-5/overview) * [Haiku 5.5 migration guide](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide) * [Messages reference](https://platform.claude.com/docs/en/api/messages/create) * [Beta Messages reference](https://platform.claude.com/docs/en/api/beta/messages/create) * [Thinking](https://platform.claude.com/docs/en/build-with-claude/thinking), [effort](https://platform.claude.com/docs/en/build-with-claude/effort), [task budgets](https://platform.claude.com/docs/en/build-with-claude/task-budgets) * [On-demand compaction](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand), [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing) * [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching), [vision](https://platform.claude.com/docs/en/build-with-claude/vision), [PDF support](https://platform.claude.com/docs/en/build-with-claude/pdf-support) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/claude-opus-5-5 Claude Opus 5.5 is Anthropic's model for long-running agentic coding and knowledge work. Send the official Anthropic Messages request to TokLab: change the base URL and the API key, keep the body. The same model also answers the OpenAI Chat Completions and Responses formats. ## Model ID | Model ID | Context window | Max output | Thinking | Default effort | | ----------------- | -------------- | ----------- | ------------------- | -------------- | | `claude-opus-5-5` | 1M tokens | 128K tokens | Adaptive, always on | `medium` | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/messages \ -H "x-api-key: $TOKLAB_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}] }' ``` ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai", ) message = client.messages.create( model="claude-opus-5-5", max_tokens=1024, messages=[{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}], ) print("".join(block.text for block in message.content if block.type == "text")) ``` ```javascript import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai", }); const message = await client.messages.create({ model: "claude-opus-5-5", max_tokens: 1024, messages: [{ role: "user", content: "Summarize the trade-offs of event sourcing in three bullet points." }], }); for (const block of message.content) if (block.type === "text") console.log(block.text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "claude-opus-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Summarize the trade-offs of event sourcing in three bullet points."}]}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/messages", bytes.NewReader(body)) req.Header.Set("x-api-key", os.Getenv("TOKLAB_API_KEY")) req.Header.Set("anthropic-version", "2023-06-01") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | The Messages endpoint forwards your request body as sent, including optional fields, and returns the official response. An `anthropic-beta` header is passed on as well. Keep the API key in server-side code. ## Parameters | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------- | ------------------- | -------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `claude-opus-5-5`. | | `max_tokens` | integer | Yes | — | 0–128000. Includes the tokens spent on thinking. `0` only pre-warms the prompt cache. | | `messages` | object\[] | Yes | — | Alternating `user` and `assistant` turns; `content` is a string or an array of content blocks. The last turn must be `user`. Exception: to continue a `pause_turn` response, send its content back as the last `assistant` message. | | `system` | string or object\[] | No | — | System prompt. | | `thinking` | object | No | `{"type": "adaptive"}` | Thinking is adaptive and always on. `display`: `omitted` (default) or `summarized`. | | `output_config.effort` | enum | No | `medium` | `low`, `medium`, `high`, `xhigh`, `max`. Steers how much the model thinks. | | `output_config.format` | object | No | — | A JSON schema for structured output. | | `stop_sequences` | string\[] | No | — | Stop when one of these strings is generated. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `temperature` | number | No | — | Only `1` (the default) is accepted, for backwards compatibility; any other value returns a 400 error. Leave it out. | | `top_p` | number | No | — | Only values from `0.99` to `1` are accepted, for backwards compatibility; any other value returns a 400 error. Leave it out. | | `top_k` | integer | No | — | Not accepted: any value returns a 400 error. Leave it out. | | `tools` | object\[] | No | — | Tool definitions. | | `tool_choice` | object | No | — | `auto` or `none`; forcing a tool (`any` or `tool`) is not supported by this model. | | `metadata.user_id` | string | No | — | An opaque id for your end user, up to 512 characters. | | `cache_control` | object | No | — | Top-level prompt-cache breakpoint. | | `container`, `context_management`, `mcp_servers`, `diagnostics`, `service_tier`, `inference_geo`, `speed` | — | No | — | Forwarded as sent. | ## Thinking and effort Claude Opus 5.5 always uses adaptive thinking: the model decides how much to think, and `output_config.effort` steers it. Higher effort usually means more output tokens, a longer wait and a higher cost. With `thinking.display` set to `summarized`, the response includes `thinking` blocks you can show; with `omitted`, they are left out. Thinking tokens are billed as output tokens. ## Media inputs Images and PDFs go in a user turn's `content` as `image` and `document` blocks, with a `url` source or, as in the official API, a `base64` source: ```json {"role": "user", "content": [ {"type": "image", "source": {"type": "url", "url": "https://example.com/chart.png"}}, {"type": "text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable file of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including thinking, * prompt-cache reads, and * prompt-cache writes, with separate 5-minute and 1-hour rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official message object: ```json { "id": "msg_...", "type": "message", "role": "assistant", "model": "claude-opus-5-5", "content": [{"type": "text", "text": "..."}], "stop_reason": "end_turn", "usage": {"input_tokens": 18, "output_tokens": 4, "cache_read_input_tokens": 0, "cache_creation_input_tokens": 0} } ``` With `"stream": true` the response is a stream of the official events: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta` and `message_stop`. The final `message_delta` carries the output token count. ## OpenAI-compatible formats The same model answers the OpenAI formats, so existing OpenAI code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="claude-opus-5-5", messages=[{"role": "user", "content": "Hello"}], ) response = client.responses.create(model="claude-opus-5-5", input="Hello") ``` These requests are converted to the Messages format, so a field with no Messages counterpart has no effect. Their responses carry the official OpenAI fields and may include a few extra usage fields; read `usage.total_tokens` and the official fields. ## Errors Errors on `/v1/messages` use the Anthropic shape, `{"type": "error", "error": {"type": "...", "message": "..."}}`; the other formats use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with the default effort and raise it only for tasks that need more thinking; effort changes both quality and cost. * Set `max_tokens` high enough for the thinking as well as the answer: it is one budget for both. * Put long, reused context first and mark it with `cache_control` so later requests read it from the cache at the lower rate. ## Related * [Claude Opus 5.5 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/claude-opus-5-5.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/claude-opus-5-5.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/claude-sonnet-5-5 Use `claude-sonnet-5-5` with the Anthropic Messages format. This document distinguishes the official request contract from the behavior observed in compatibility tests. Some advanced options do not yet behave as specified; review the limitations before depending on them. See the [pricing page](https://toklab.ai/pricing) for current input, output and cache prices. ## Quick start ```bash curl https://api.toklab.ai/v1/messages \ -H "x-api-key: $TOKLAB_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Explain how a rainbow forms in three sentences."}] }' ``` ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai", ) message = client.messages.create( model="claude-sonnet-5-5", max_tokens=1024, messages=[{"role": "user", "content": "Explain how a rainbow forms in three sentences."}], ) print("".join(block.text for block in message.content if block.type == "text")) ``` ```javascript import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai", }); const message = await client.messages.create({ model: "claude-sonnet-5-5", max_tokens: 1024, messages: [{ role: "user", content: "Explain how a rainbow forms in three sentences." }], }); for (const block of message.content) if (block.type === "text") console.log(block.text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "claude-sonnet-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Explain how a rainbow forms in three sentences."}]}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/messages", bytes.NewReader(body)) req.Header.Set("x-api-key", os.Getenv("TOKLAB_API_KEY")) req.Header.Set("anthropic-version", "2023-06-01") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` `POST /v1/messages` accepts `x-api-key` or Bearer authentication and `anthropic-version: 2023-06-01`. Send an `anthropic-beta` header for features whose official documentation requires one. Keep credentials in server-side code. The model also accepts basic OpenAI Chat Completions (`POST /v1/chat/completions`) and Responses (`POST /v1/responses`) requests. Use Messages for the native parameters described below; OpenAI format conversion does not provide every Anthropic feature. ## Official parameter contract Sonnet 5.5 has a 1M-token context window and a synchronous output limit of 128000 tokens. Batch-specific output limits do not apply to this endpoint. Optional properties have no application-supplied default unless the table says otherwise. | Parameter | Type / required | Official constraints and defaults | | --------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string, required | `claude-sonnet-5-5`. | | `max_tokens` | integer, required | 0–128000, including thinking tokens. Officially, 0 populates the prompt cache without generating output; see the current limitation below. | | `messages` | object array, required | At least one conversation message, at most 100000. Each has `role` and `content`; content is a string or content-block array. Ordinary turns use `user`/`assistant`. Mid-conversation `system` messages follow the official placement rules. | | `system` | string or text-block array | Top-level instructions. Text blocks can include cache breakpoints. | | `thinking` | object | Default: `{"type":"adaptive"}`. The other supported mode is `{"type":"between_tools"}`. Manual budgets and `disabled` are rejected. | | `thinking.display` | enum | Adaptive mode only: `omitted` (default) or `summarized`. An omitted summary does not mean thinking is disabled. | | `thinking.block_binding` | object, beta | Adaptive mode only. Requires `thinking-binding-controls-2026-08-01`; follow the official preserved-thinking contract. | | `output_config.effort` | enum or null | `low`, `medium`, `high`, `xhigh`, `max`; default `high`. Null leaves the default in effect. | | `output_config.format` | object or null | Structured JSON output: `{"type":"json_schema","schema":{...}}`. Use the supported JSON Schema subset. | | `stream` | boolean | Default `false`; `true` returns SSE events. | | `stop_sequences` | string array | Officially stops generation at a matching string. The current compatibility test did not enforce this behavior. | | `temperature` | number or null | Only 1 is accepted for compatibility; omit it. Other non-null values are rejected. | | `top_p` | number or null | Only 0.99–1 is accepted for compatibility; omit it. | | `top_k` | no non-null value | Sampling is unsupported; omit this property. | | `tools` | object array | Client tools have `name`, `input_schema`, and optional description / strictness settings. Server tools use their versioned official definitions. | | `tool_choice` | object | `auto` (default) or `none`. `any` and named forced `tool` are rejected. `auto` may include `disable_parallel_tool_use`. | | `metadata.user_id` | string or null | At most 512 characters; use an opaque identifier. | | `cache_control` | object or null | `type: "ephemeral"`; `ttl: "5m"` (default) or `"1h"`. Sonnet 5.5 requires at least 512 cacheable tokens. Block-level cache breakpoints are also supported by the official API. | | `diagnostics` | object or null | `previous_message_id`: string of at most 256 characters or null. Requests cache-divergence diagnostics. | | `service_tier` | enum | `auto` (default) or `standard_only`. | | `speed` | enum or null | Omit or use `standard` / null. Sonnet 5.5 does not support `fast`. | | `inference_geo` | string or null | The official default comes from the account settings. An accepted request alone does not verify geographic processing. | | `fallbacks` | string, object array or null, beta | `"default"` or up to three fallback entries. Each requires `model`; optional overrides are `max_tokens`, `thinking`, `output_config` and `speed`. See the fallback rules below. | | `fallback_credit_token` | string, object or null | A token from a prior refusal, or `{"token":"...","mode":"strict"}`. Object form requires `fallback-credit-2026-07-01`; mode is `strict` (default) or `best_effort`. Cannot accompany a non-null `fallbacks` value. | | `container` | string, object or null | Container ID, or container configuration with optional `id` and `skills` (at most 20). Skills use the official type, identifier and version fields. | | `context_management` | object or null | Official context-edit configuration, including `edits`; null omits the setting. Model-specific edit compatibility still applies. | | `mcp_servers` | object array | Official MCP server definitions, subject to the required beta version and server authentication. An empty-array probe does not verify remote MCP execution. | | `compaction` | object or null, beta | `{"type":"summarize"}`, with `compact-2026-09-04`; null omits compaction. Enabled compaction cannot be combined with non-null `context_management`, stop sequences or structured-output format. The signed compaction behavior did not pass the current test. | | `messages[].output_config.effort` | enum, beta | Per-message effort on a system message; requires `mid-conversation-output-config-2026-07-01`. Effort-only system messages may appear anywhere; content-bearing system groups follow the official placement rules. It must not change effort in `between_tools` mode. | `between_tools` accepts only its `type` property and effort `low`, `medium` or `high`. Do not send `display`, `budget_tokens` or `block_binding` with it. Example: ```json { "model": "claude-sonnet-5-5", "max_tokens": 1024, "thinking": {"type": "between_tools"}, "output_config": {"effort": "medium"}, "messages": [{"role": "user", "content": "Explain this concept briefly."}] } ``` Assistant prefilling is unsupported. To continue a `pause_turn`, replay the returned server-tool assistant content unchanged. Compaction summarizes existing history and is not an assistant prefill. Preserve thinking blocks and signatures exactly; do not move them between models or edit earlier history without following the official binding rules. On the native Claude API, computer use requires `computer_toolset_20260801`; `computer_20251124` is rejected. Advisor configurations using `claude-opus-4-8`, `claude-opus-4-7` or `claude-sonnet-5` are also rejected for this executor. ## Fallback request fields The official `fallbacks` beta retries eligible classifier refusals. It does not retry rate limits, overloads or server errors, and a refusal may remain unresolved. Send `server-side-fallback-2026-07-01` for `"default"` or an explicit list; `server-side-fallback-2026-06-01` supports the list only. Other dated versions are rejected. An explicit list contains at most three entries with distinct models, none equal to the requested model. Allowed targets come from the beta Models API's `allowed_fallback_models`. Only `model`, `max_tokens`, `thinking`, `output_config` and `speed` are permitted per entry; overrides must be valid for that target. The July beta converts Sonnet 5.5 `between_tools` to Sonnet 5 `disabled` with omitted display when that fallback occurs. With the June beta, provide the Sonnet 5 thinking override yourself. `fallback_credit_token` is for a separate retry after a refusal. A string selects strict redemption; an object adds `mode`. In `strict` mode, failed redemption rejects the retry. In `best_effort` mode, a token-layer failure can proceed at the normal price and is recorded in `usage.fallback_credit`; malformed tokens and combining credit with `fallbacks` still fail. Redemption also requires the eligible request, account, workspace, platform and five-minute window described in the [official credit guide](https://platform.claude.com/docs/en/build-with-claude/fallback-credit). A benign request with `fallbacks: "default"`, the July beta header and `speed: "standard"` returned the expected text. This establishes acceptance only: fallback execution and credit redemption have **not been verified end to end** here. ## Media and tool inputs Images use `image` blocks and PDFs use `document` blocks in a user message. The official source types include public URLs and base64 with the corresponding MIME type. The compatibility checks used a base64 PNG and a one-page base64 PDF, and verified the contents of the answers. They did not exercise every URL, file-size, image-resolution or PDF-page boundary. Client-side tools use the standard `tool_use` → `tool_result` exchange. Keep tool-use IDs unchanged and return the result in a user message. A successful strict-tool example verifies that example's arguments, not every supported JSON Schema keyword. ## Responses A non-streaming response contains `id`, `type: "message"`, `role: "assistant"`, `model`, `content`, `stop_reason`, `stop_sequence` and `usage`, plus optional official fields such as `container`, `diagnostics`, `context_management`, `stop_details` and beta response fields. Content can include text, thinking, tool calls, tool results or other official block types; do not assume the first block is text. With streaming, handle `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta` and `message_stop`. Errors can also occur inside a stream. Usage can include ordinary input/output tokens, thinking-token details, cache reads, and separate 5-minute / 1-hour cache creation counts. An official classifier refusal is a normal response with `stop_reason: "refusal"` and `stop_details`, rather than an HTTP error. In a fallback response, `model` identifies the model that answered, `fallback` content blocks mark transitions, and `usage.iterations` describes the attempts. Inspect these fields instead of assuming the requested model served the response. These response behaviors remain unverified here. Messages errors use `{"type":"error","error":{"type":"...","message":"..."}}`. Failed requests are not charged. ## Compatibility verification: 2026-10-01 | Result | Checked behavior | | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Observed working | Basic text, ordinary multi-turn recall, non-conflicting string/block system instructions, streaming, adaptive and between-tools requests, JSON output, auto/none tools, a strict tool call, tool-result replay, base64 image/PDF inputs, and 5m/1h cache-write/read usage. | | Rejected according to the model contract | Invalid output-token budgets, removed sampling settings, manual/disabled thinking, invalid between-tools combinations, forced tools, assistant prefill, legacy computer tools, and oversized metadata IDs. | | Accepted, effect not established | All five effort levels, summarized thinking, binding settings, metadata, service tier, region selection, diagnostics, an empty context-edit list, null container, empty MCP list and computer-toolset declaration. Toolset declaration does not establish successful computer use. | | Known mismatch | `max_tokens: 0` returned 400. A stop-sequence request returned the stop string and trailing text. On-demand compaction returned ordinary text rather than a signed compaction block. | | Additional behavior requiring investigation | A per-message effort request did not recall the earlier value; a conflicting system/user instruction probe followed the user instruction. These results do not establish that every system prompt or multi-turn request fails. | Beta tool execution, real MCP connections, Files API references, geographic residency, thinking-signature replay, full context/output ceilings, media boundary cases and refusal/fallback behavior have not been validated end to end. HTTP 200 and a returned model name do not authenticate which model ran or prove all supplied options took effect. ## References * [Official Sonnet 5.5 overview](https://platform.claude.com/docs/en/models/sonnet-5-5/overview) * [Sonnet 5.5 changes and restrictions](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5) * [Messages parameter reference](https://platform.claude.com/docs/en/api/messages/create) * [Per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort) * [On-demand compaction](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand) * [Refusals and fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback) * [Fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit) * [OpenAPI schema](https://toklab.ai/docs/claude-sonnet-5-5.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/claude-sonnet-5-5.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/deepseek-v4-1-flash DeepSeek V4.1 Flash is DeepSeek's fast, low-cost model (DeepSeek's own API calls it `deepseek-flash`). It thinks before it answers by default, and you can turn thinking off or set its effort per request. Send the official DeepSeek request to TokLab: change the base URL and the API key, keep the body. ## Model ID | Model ID | Context window | Max output | Reasoning effort | Default | | --------------------- | -------------- | --------------------- | ---------------------------- | ------------------- | | `deepseek-v4.1-flash` | 1M tokens | 384K tokens (393,216) | `none`, `low`, `high`, `max` | Thinking on, `high` | Input: text and images. Output: text. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/chat/completions \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-v4.1-flash", "messages": [{"role": "user", "content": "Give me three names for a coffee shop."}] }' ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1", ) completion = client.chat.completions.create( model="deepseek-v4.1-flash", messages=[{"role": "user", "content": "Give me three names for a coffee shop."}], ) print(completion.choices[0].message.content) ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai/v1", }); const completion = await client.chat.completions.create({ model: "deepseek-v4.1-flash", messages: [{ role: "user", content: "Give me three names for a coffee shop." }], }); console.log(completion.choices[0].message.content); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "deepseek-v4.1-flash", "messages": [{"role": "user", "content": "Give me three names for a coffee shop."}]}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ------------------ | ------------------------------------------------ | ----------------------------------------------------------------------------- | | Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | All three return DeepSeek's official response format, streaming or not. Keep the API key in server-side code. ## Parameters Chat Completions fields: | Name | Type | Required | Default | Notes | | --------------------------------------- | ------------------- | -------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `deepseek-v4.1-flash`. | | `messages` | object\[] | Yes | — | Text messages; images as `image_url` parts (see [Image input](#image-input)). | | `thinking.type` | enum | No | `enabled` | `enabled` or `disabled`. | | `reasoning_effort` | enum | No | `high` | `none` (thinking off), `low`, `high` or `max`. `minimal` runs as `low`, `medium` and `xhigh` as `high`. | | `max_tokens` | integer | No | 8K, or 64K with thinking (128K at `max` effort) | 1–393216. Includes the reasoning. | | `stop` | string or string\[] | No | — | Stop sequences. | | `response_format` | object | No | `{"type": "text"}` | `text` or `json_object`. `json_schema` returns 400. | | `tools` | object\[] | No | — | Function tools; `strict` is accepted. | | `tool_choice` | string or object | No | `none` without tools, `auto` with tools | `auto` and `none` are applied. `required` and a named function are accepted but do not force a call. | | `stream` | boolean | No | `false` | Stream server-sent events. | | `stream_options.include_usage` | boolean | No | `false` | Every chunk carries `usage`, `null` except on the last. | | `temperature` | number | No | 1 | 0–2. No effect in thinking mode. | | `top_p` | number | No | 1 | 0–1. In thinking mode values below 0.95 run as 0.95; without thinking it stays 1. | | `user_id` | string | No | — | Your end-user identifier. | | `logprobs`, `top_logprobs` | — | No | — | Accepted (`top_logprobs` 0–20), but no log probabilities are returned. | | `frequency_penalty`, `presence_penalty` | — | No | — | Deprecated by DeepSeek: accepted, no effect. | ## Thinking and effort Thinking is on by default at `high` effort. Turn it off with `"thinking": {"type": "disabled"}` or `"reasoning_effort": "none"`; the answer then comes straight away and costs fewer output tokens. `max` spends the most reasoning on hard problems. The reasoning comes back in `reasoning_content`, next to `content`, and is billed as output tokens. When a request carries `tools`, send every earlier assistant message back with its `reasoning_content`, as DeepSeek requires in tool-call conversations. ## Image input Images go in a user message's `content` as `image_url` parts, either a public `http(s)` URL or a base64 data URI: ```json {"role": "user", "content": [ {"type": "image_url", "image_url": {"url": "https://example.com/chart.png"}}, {"type": "text", "text": "What does this chart show?"} ]} ``` A URL may be at most 8192 characters and point to an image of at most 32 MiB. Replace the example URL with a publicly reachable image of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens that miss the cache (`prompt_cache_miss_tokens`), * input tokens that hit the cache (`prompt_cache_hit_tokens`), * output tokens, including reasoning. Rates depend on when the request runs. Peak hours are 01:00–04:00 and 06:00–10:00 UTC, Monday to Friday; every other hour, weekends included, is off-peak at half the peak rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming Chat Completions request returns: ```json { "id": "bc86988e-...", "object": "chat.completion", "created": 1790585983, "model": "deepseek-v4.1-flash", "choices": [{ "index": 0, "finish_reason": "stop", "logprobs": null, "message": {"role": "assistant", "reasoning_content": "...", "content": "..."} }], "usage": { "prompt_tokens": 36, "completion_tokens": 39, "total_tokens": 75, "prompt_cache_hit_tokens": 0, "prompt_cache_miss_tokens": 36, "prompt_tokens_details": {"cached_tokens": 0}, "completion_tokens_details": {"reasoning_tokens": 0} } } ``` With `"stream": true` each chunk carries a `delta` with `reasoning_content` or `content`, and the last chunk before `data: [DONE]` carries the usage. ## Responses API and Codex `POST /v1/responses` takes the Responses body: `input`, `instructions`, `max_output_tokens`, `reasoning.effort` (as `reasoning_effort` above), `text.format` (`text` or `json_object`; `json_schema` is accepted but not enforced), `tools` (`function` and the `apply_patch` custom tool), `tool_choice`, `temperature`, `top_p`, `top_logprobs`, `user` and `stream`. The reasoning comes back as a `reasoning` item with `reasoning_text` content, and a stream carries numbered events from `response.created` to `response.completed`, with the reasoning in `response.reasoning_text.delta` events. The API is stateless: `previous_response_id`, `conversation` and built-in tools such as `web_search` are ignored, so send the whole conversation in `input`. To use DeepSeek V4.1 Flash in Codex, add a provider to `~/.codex/config.toml` and set `TOKLAB_API_KEY`: ```toml model = "deepseek-v4.1-flash" model_provider = "toklab" show_raw_agent_reasoning = true [model_providers.toklab] name = "TokLab" base_url = "https://api.toklab.ai/v1" env_key = "TOKLAB_API_KEY" wire_api = "responses" ``` ## Anthropic Messages format Code written for the Anthropic Messages API can call DeepSeek V4.1 Flash too: send the Messages body to `/v1/messages` with `"model": "deepseek-v4.1-flash"`. `system`, `max_tokens`, `tools`, `tool_choice` (`auto`, `none`), `thinking` (`enabled`, `disabled`) and `temperature` (0–2) are applied; `output_config.effort` and `metadata.user_id` are accepted; `top_k`, `stop_sequences` and `tool_choice` `any` have no effect. The reasoning comes back as `thinking` blocks. Images go in as `base64` or `url` sources. ## Errors Errors use `{"error": {"code": ..., "message": "..."}}` (the Messages endpoint uses Anthropic's error shape). The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Turn thinking off for simple, fast steps such as classification or extraction; keep it on for reasoning, math and code. * Keep long, reused context at the start of the prompt: cached input is billed at a fraction of the input rate. * Run large batch jobs off-peak, when every rate is half. ## Related * [DeepSeek V4.1 Flash pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/deepseek-v4-1-flash.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/deepseek-v4-1-flash.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/flux-3-image-klein ## Quick example Submit one image request, save the returned `id`, and poll until the task is `completed` or `failed`. This API uses asynchronous tasks and URL outputs. ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H 'Content-Type: application/json' \ -d '{"model":"flux-3-image-klein","prompt":"An amber bottle on pale limestone in soft morning light","resolution":"1k","aspect_ratio":"3:2"}' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={"model": "flux-3-image-klein", "prompt": "An amber bottle on pale limestone in soft morning light", "resolution": "1k", "aspect_ratio": "3:2"}, timeout=60, ) response.raise_for_status() task = response.json() print(task["id"]) ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'flux-3-image-klein', prompt: 'An amber bottle on pale limestone in soft morning light', resolution: '1k', aspect_ratio: '3:2' }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const task = await response.json(); console.log(task.id); ``` ```php true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('TOKLAB_API_KEY'), 'Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['model' => 'flux-3-image-klein', 'prompt' => 'An amber bottle on pale limestone in soft morning light', 'resolution' => '1k', 'aspect_ratio' => '3:2']), ]); $response = curl_exec($ch); if ($response === false) throw new RuntimeException('Submission could not be confirmed'); echo $response; curl_close($ch); ``` ## Endpoint and headers `POST https://api.toklab.ai/v1/images/generations` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | Keep the key on your server. An HTTP success acknowledges a task; it does not mean that its image is ready. ## Parameters There are 11 accepted fields. Only `model` and `prompt` are required. Omit optional fields to use their defaults; `null` is not accepted. | Field | Type | Default | Constraint | | ------------------ | ------------ | -------- | ------------------------------------------------------------------------------------------ | | `model` | string | Required | `flux-3-image-klein` | | `prompt` | string | Required | Non-empty image description or edit instruction | | `image_urls` | string array | None | At most 10 public HTTP(S) image URLs, without credentials; empty array means no references | | `aspect_ratio` | string | `auto` | A listed ratio; also accepts forms such as `16x9` | | `size` | string | None | Compatibility alias for aspect ratio; prefer `aspect_ratio` and send only one | | `resolution` | string | `1k` | `768sq`, `1k`, `1.5k`, `2k`, `4k`; case insensitive; `768` aliases `768sq` | | `safety_tolerance` | integer | `2` | 0–4; 0 is strictest | | `seed` | integer | Random | 0–4294967295; explicit 0 is preserved | | `steps` | integer | `16` | 1–16 | | `output_format` | string | `jpeg` | `jpeg`, `png`; `jpg` aliases `jpeg` | | `n` | integer | `1` | Only 1 | Ratios: `auto`, `21:9`, `2:1`, `16:9`, `3:2`, `7:5`, `4:3`, `5:4`, `1:1`, `4:5`, `3:4`, `5:7`, `2:3`, `9:16`, `1:2`, `9:21`. Safety values above 2 are API only, except for administrators. ## Modes and constraints No references means text-to-image. One reference enables editing; multiple references enable composition from several images. With `auto`, edits follow the first reference's aspect ratio. Text-only generation uses the prompt to select a frame, falling back to `1:1` when no frame is determined. Resolution defaults to `1k` in every mode. Resolution tiers represent approximate image scale: 768sq is about 768 × 768; 1K is about 1 MP; 1.5K about 2 MP; 2K about 4 MP; 4K about 16 MP. Inspect the returned file for actual dimensions. This endpoint does not accept `width`, `height`, pixel dimensions in `size`, `negative_prompt`, `guidance`, `grounding`, `prompt_upsampling`, `mask`, or `mask_url`. Unknown fields return HTTP 400 before billing. WebP output, base64 input, streaming, and callbacks are not offered. ## Reference images and regional edits Upload references to a public URL before submitting. The request body contains URLs, never file bytes or data URLs. ```json { "model": "flux-3-image-klein", "prompt": "Use Image 1 as the subject and Image 2 as the setting; match the perspective and light", "image_urls": ["https://example.com/subject.png", "https://example.com/setting.png"], "aspect_ratio": "auto", "resolution": "2k", "seed": 0, "steps": 16, "output_format": "png" } ``` Replace these placeholder URLs with your own accessible images. References are ordered: `ref_image_0` is the first. Bounding-box instructions are part of the `prompt` string, not a separate request field. Coordinates use `[y1, x1, y2, x2]` normalized to 0–1000. A layout object can contain `id`, `bbox`, and `desc`; an edit can use `id`, `from`, `src_bbox`, `tgt_bbox`, and `desc`. JSON-encode the complete request so quotes inside the prompt are escaped correctly. ## Billing One successful request is one image. The selected resolution alone sets the price; steps, seed, aspect ratio, reference count, and format do not add fees. Text-to-image and editing have the same rate. Failed requests are not charged. See [live pricing](https://toklab.ai/pricing). ## Task response and polling Submission: ```json {"id":"task_example","model":"flux-3-image-klein","status":"processing"} ``` ```bash curl https://api.toklab.ai/v1/tasks/task_example \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Completed task (illustrative URL): ```json { "id": "task_example", "model": "flux-3-image-klein", "status": "completed", "output": {"data": [{"url": "https://file.deepytb.com/generated/example.png"}]} } ``` Read `output.data[0].url`. Allow up to ten minutes for generation, especially at 4K. Polling is read-only; a client timeout is not permission to submit another paid request. Public task responses do not include costs or account balances. ## Errors HTTP errors use `{"error": {"code": integer, "message": string}}`. See the [shared error directory](https://toklab.ai/docs/api/errors). A failed task exposes its error alongside `status: "failed"`. Correct invalid parameters before resubmitting; retain the task ID when checking a submitted request. ## Tips and related guides Use positive descriptions and name the regions or details to preserve. Lower steps may alter quality without reducing the price. Compare one change at a time. * [FLUX 3 Image Klein pricing](https://toklab.ai/pricing) * [Task lifecycle](https://toklab.ai/docs/api/tasks) --- Source: https://toklab.ai/docs/gemini-3-1-flash-image Nano Banana 2 is Google's Gemini 3.1 Flash Image model. Send Google's `generateContent` request body with a `model` field, keep the returned task ID, and check that task for the finished image. Reference images go in `contents` as `fileData` URLs. ## Model IDs | Model ID | Channel | Billing | | --------------------------------- | -------- | ---------------------------------------------------------------- | | `gemini-3.1-flash-image` | Standard | One flat price per delivered image | | `gemini-3.1-flash-image-official` | Official | Per-token rates for input, text/thinking output and image output | Both IDs accept the same parameters. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3.1-flash-image", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gemini-3.1-flash-image", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"}, }, }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gemini-3.1-flash-image', contents: [{ parts: [{ text: 'A ceramic teapot on a linen tablecloth, soft window light' }] }], generationConfig: { responseModalities: ['IMAGE'], imageConfig: { aspectRatio: '16:9', imageSize: '2K' }, }, }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gemini-3.1-flash-image", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The body is Google's `generateContent` request with one addition: `model`, because this endpoint carries no model in its path. The response contains a task ID, not the finished image. Keep API keys in server-side code. Calling `/v1beta/models/...:generateContent` directly is not supported; use this endpoint. ## Parameters | Name | Type | Required | Default | Notes | | ------------------------------------------------- | ---------- | -------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | One of the two model IDs above. | | `contents` | Content\[] | Yes | — | 1–32 turns. Each has `parts` and an optional `role` (`user` or `model`); the last turn is `user`. | | `contents[].parts[].text` | string | — | — | A text part. At least one text part is required. | | `contents[].parts[].fileData` | object | No | — | `{"mimeType": "...", "fileUri": "https://..."}`; an image, video, or PDF reference. Up to 14 in total. | | `systemInstruction` | object | No | — | `{"parts": [{"text": "..."}]}`. | | `safetySettings` | object\[] | No | — | `{"category", "threshold"}` pairs; see below. | | `generationConfig.responseModalities` | enum\[] | No | text and image | `["IMAGE"]` for images only, or `["TEXT", "IMAGE"]`. | | `generationConfig.imageConfig.aspectRatio` | enum | No | Input image ratio, else `1:1` | `1:1`, `1:4`, `4:1`, `1:8`, `8:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`. | | `generationConfig.imageConfig.imageSize` | enum | No | `1K` | `512`, `1K`, `2K`, `4K`. Uppercase `K`. | | `generationConfig.candidateCount` | integer | No | `1` | Only `1`. One request returns one image. | | `generationConfig.temperature` | number | No | Model default | 0–2. | | `generationConfig.topP` | number | No | Model default | 0–1. | | `generationConfig.topK` | integer | No | Model default | 1 or more. | | `generationConfig.seed` | integer | No | — | 32-bit integer. | | `generationConfig.maxOutputTokens` | integer | No | Model default | 1–32,768. | | `generationConfig.stopSequences` | string\[] | No | — | Up to 5. | | `generationConfig.mediaResolution` | enum | No | Model default | `MEDIA_RESOLUTION_LOW`, `MEDIA_RESOLUTION_MEDIUM`, `MEDIA_RESOLUTION_HIGH`. Sets how many tokens input media use. | | `generationConfig.thinkingConfig.includeThoughts` | boolean | No | `false` | Return the model's thought summaries as `output.thoughts`. | | `generationConfig.responseFormat.image` | object | No | — | `mimeType`: `IMAGE_JPEG`; `delivery`: `INLINE`; `aspectRatio` and `imageSize` as Google's enums, e.g. `ASPECT_RATIO_SIXTEEN_BY_NINE` and `IMAGE_SIZE_TWO_K`, covering the same ratios and sizes as `imageConfig`. | Safety categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`, `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`. Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`, `BLOCK_LOW_AND_ABOVE`, `OFF`. Unknown fields are rejected. Not yet available: Google Search grounding (`tools`) and cached content; `thinkingLevel` is not documented for this model. `inlineData` is not accepted; pass media as `fileData` URLs. `responseFormat.image.delivery` accepts only `INLINE`: finished images are always returned as hosted URLs. ### Output size | `imageSize` | 1:1 output | Image tokens | | ----------- | ---------- | ------------ | | `512` | 512×512 | 747 | | `1K` | 1024×1024 | 1,120 | | `2K` | 2048×2048 | 1,680 | | `4K` | 4096×4096 | 2,520 | Other aspect ratios keep the same token count; for example `16:9` at `1K` is 1376×768. ## Modes There is no separate mode parameter or editing endpoint. | Operation | Parameters | | --------------- | ----------------------------------------------------------------------------- | | Text to image | a text part | | Edit or compose | text part + one or more `fileData` parts | | Multi-turn edit | earlier `user` and `model` turns, then a new `user` turn (see the note below) | To continue a conversation, rebuild the `model` turn from the previous task's `output.parts`, in order: a text part becomes `{"text": ..., "thoughtSignature": ...}` and an image part becomes `{"fileData": {"mimeType": "image/", "fileUri": }, "thoughtSignature": ...}`. Keep each `thoughtSignature` exactly as returned: it is the URL of the signature we stored for you (a 4K image's signature is several megabytes), and we restore it before the request reaches the model. Only signatures from your own task results are accepted. ### Edit with a reference image ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3.1-flash-image", "contents": [{ "role": "user", "parts": [ {"text": "Turn this photo into a watercolor painting. Keep the composition."}, {"fileData": {"mimeType": "image/jpeg", "fileUri": "https://example.com/photo.jpg"}} ] }] }' ``` Replace the example URL with your own accessible image. ## Media inputs This API accepts URL references only. Base64 `inlineData`, `data:` URLs, and multipart uploads are not accepted. References must be public HTTP(S) URLs, each smaller than 50 MB and 100 MB in total: images (`image/png`, `image/jpeg`, `image/webp`, `image/heic`, `image/heif`), videos (`video/mp4`, `video/mpeg`, `video/mov`, `video/avi`, `video/x-flv`, `video/mpg`, `video/webm`, `video/wmv`, `video/3gpp`), or PDF documents (`application/pdf`). `mimeType` must match the file. URLs are fetched during processing; an inaccessible image fails the task, and a failed task is not charged. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. `gemini-3.1-flash-image` charges one flat price per delivered image, whatever the size or prompt. `gemini-3.1-flash-image-official` charges by usage: input tokens (text and reference images), text and thinking output tokens, and image output tokens, each at its own rate. The image size is the main factor; see the table above. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns a task reference: ```json { "id": "task_...", "model": "gemini-3.1-flash-image", "status": "processing", "created_at": 1790310979 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Poll every few seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Complete polling example Run this after the Python submission example above. ```python import time deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task ```json { "id": "task_...", "model": "gemini-3.1-flash-image", "status": "completed", "created_at": 1790310979, "finished_at": 1790311001, "output": { "created": 1790310999, "data": [{"url": "https://cdn.example.com/media/tasks/task_example/0.jpg"}], "output_format": "jpeg", "usage": { "input_tokens": 27, "output_tokens": 1525, "total_tokens": 1552, "output_tokens_details": {"image_tokens": 1120, "text_tokens": 405, "reasoning_tokens": 0} } } } ``` | Field | Meaning | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Keep this ID for subsequent queries. | | `status` | `processing`, `completed`, or `failed`. | | `created_at`, `finished_at` | Unix timestamps in seconds. | | `output.data[].url` | The generated image URL. | | `output.text` | Text the model returned alongside the image, when `responseModalities` includes `TEXT`. Thoughts are not included. | | `output.thoughts` | The model's thought summaries, when `includeThoughts` is `true`. Interim images the model draws while thinking are not delivered. | | `output.output_format` | Actual image format. | | `output.parts` | The final response parts in order, for multi-turn editing: `{"text", "thoughtSignature"}` or `{"image": , "thoughtSignature"}`. `thoughtSignature` is a URL; send it back unchanged. | | `output.usage` | Token usage. `output_tokens` counts text, thinking, and image output; `output_tokens_details.image_tokens` is the image part. | | `error` | Structured error on a failed task. | Streaming (`streamGenerateContent`) is not supported; results are delivered through the task. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. An image withheld by the model's safety filters fails with `content_policy_violation`; a response with no image fails with `no_output`. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your task history before submitting again: the first request may have been accepted. ## Tips * Describe subject, setting, lighting, and style in full sentences. * For an edit, say what should change and what must stay the same. * Use `512` or `1K` for drafts, and `2K` or `4K` for final assets. * Save returned images to your own storage when you need a durable copy. ## Related * [Nano Banana 2 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gemini-3-1-flash-image.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gemini-3-1-flash-image.md) --- Source: https://toklab.ai/docs/gemini-3-1-flash-lite-image Nano Banana 2 Lite is Google's Gemini 3.1 Flash Lite Image model, the low-latency, low-cost member of the family. It renders at 1K. Send Google's `generateContent` request body with a `model` field, keep the returned task ID, and check that task for the finished image. Reference images go in `contents` as `fileData` URLs. ## Model IDs | Model ID | Channel | Billing | | -------------------------------------- | -------- | ---------------------------------------------------------------- | | `gemini-3.1-flash-lite-image-official` | Official | Per-token rates for input, text/thinking output and image output | Nano Banana 2 Lite is sold on token billing only. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3.1-flash-lite-image-official", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "1K"} } }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gemini-3.1-flash-lite-image-official", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "1K"}, }, }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gemini-3.1-flash-lite-image-official', contents: [{ parts: [{ text: 'A ceramic teapot on a linen tablecloth, soft window light' }] }], generationConfig: { responseModalities: ['IMAGE'], imageConfig: { aspectRatio: '16:9', imageSize: '1K' }, }, }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gemini-3.1-flash-lite-image-official", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "1K"} } }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The body is Google's `generateContent` request with one addition: `model`, because this endpoint carries no model in its path. The response contains a task ID, not the finished image. Keep API keys in server-side code. Calling `/v1beta/models/...:generateContent` directly is not supported; use this endpoint. ## Parameters | Name | Type | Required | Default | Notes | | ------------------------------------------------- | ---------- | -------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | The model ID above. | | `contents` | Content\[] | Yes | — | 1–32 turns. Each has `parts` and an optional `role` (`user` or `model`); the last turn is `user`. | | `contents[].parts[].text` | string | — | — | A text part. At least one text part is required. | | `contents[].parts[].fileData` | object | No | — | `{"mimeType": "...", "fileUri": "https://..."}`; an image, video, or PDF reference. Up to 14 in total. | | `systemInstruction` | object | No | — | `{"parts": [{"text": "..."}]}`. | | `safetySettings` | object\[] | No | — | `{"category", "threshold"}` pairs; see below. | | `generationConfig.responseModalities` | enum\[] | No | text and image | `["IMAGE"]` for images only, or `["TEXT", "IMAGE"]`. | | `generationConfig.imageConfig.aspectRatio` | enum | No | Input image ratio, else `1:1` | `1:1`, `1:4`, `4:1`, `1:8`, `8:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`. | | `generationConfig.imageConfig.imageSize` | enum | No | `1K` | `1K` only. | | `generationConfig.candidateCount` | integer | No | `1` | Only `1`. One request returns one image. | | `generationConfig.temperature` | number | No | Model default | 0–2. | | `generationConfig.topP` | number | No | Model default | 0–1. | | `generationConfig.topK` | integer | No | Model default | 1 or more. | | `generationConfig.seed` | integer | No | — | 32-bit integer. | | `generationConfig.maxOutputTokens` | integer | No | Model default | 1–4,096. | | `generationConfig.stopSequences` | string\[] | No | — | Up to 5. | | `generationConfig.mediaResolution` | enum | No | Model default | `MEDIA_RESOLUTION_LOW`, `MEDIA_RESOLUTION_MEDIUM`, `MEDIA_RESOLUTION_HIGH`. Sets how many tokens input media use. | | `generationConfig.thinkingConfig.includeThoughts` | boolean | No | `false` | Return the model's thought summaries as `output.thoughts`. | | `generationConfig.thinkingConfig.thinkingLevel` | enum | No | `MINIMAL` | `MINIMAL` or `HIGH`. | Safety categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`, `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`. Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`, `BLOCK_LOW_AND_ABOVE`, `OFF`. Unknown fields are rejected. Not yet available: Google Search grounding (`tools`) and cached content. `inlineData` is not accepted; pass media as `fileData` URLs. ### Output size | `imageSize` | 1:1 output | Image tokens | | ----------- | ---------- | ------------ | | `1K` | 1024×1024 | 1,120 | Other aspect ratios keep the same token count. ## Modes There is no separate mode parameter or editing endpoint. | Operation | Parameters | | --------------- | ----------------------------------------------------------------------------- | | Text to image | a text part | | Edit or compose | text part + one or more `fileData` parts | | Multi-turn edit | earlier `user` and `model` turns, then a new `user` turn (see the note below) | To continue a conversation, rebuild the `model` turn from the previous task's `output.parts`, in order: a text part becomes `{"text": ..., "thoughtSignature": ...}` and an image part becomes `{"fileData": {"mimeType": "image/", "fileUri": }, "thoughtSignature": ...}`. Keep each `thoughtSignature` exactly as returned: it is the URL of the signature we stored for you (a 4K image's signature is several megabytes), and we restore it before the request reaches the model. Only signatures from your own task results are accepted. ### Edit with a reference image ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3.1-flash-lite-image-official", "contents": [{ "role": "user", "parts": [ {"text": "Turn this photo into a watercolor painting. Keep the composition."}, {"fileData": {"mimeType": "image/jpeg", "fileUri": "https://example.com/photo.jpg"}} ] }] }' ``` Replace the example URL with your own accessible image. ## Media inputs This API accepts URL references only. Base64 `inlineData`, `data:` URLs, and multipart uploads are not accepted. References must be public HTTP(S) URLs, each smaller than 50 MB and 100 MB in total: images (`image/png`, `image/jpeg`, `image/webp`, `image/heic`, `image/heif`), videos (`video/mp4`, `video/mpeg`, `video/mov`, `video/avi`, `video/x-flv`, `video/mpg`, `video/webm`, `video/wmv`, `video/3gpp`), or PDF documents (`application/pdf`). `mimeType` must match the file. URLs are fetched during processing; an inaccessible image fails the task, and a failed task is not charged. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. `gemini-3.1-flash-lite-image-official` charges by usage: input tokens (text and reference images), text and thinking output tokens, and image output tokens, each at its own rate. Image output is the main factor; every image is 1K. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns a task reference: ```json { "id": "task_...", "model": "gemini-3.1-flash-lite-image-official", "status": "processing", "created_at": 1790310979 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Poll every few seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Complete polling example Run this after the Python submission example above. ```python import time deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task ```json { "id": "task_...", "model": "gemini-3.1-flash-lite-image-official", "status": "completed", "created_at": 1790310979, "finished_at": 1790311001, "output": { "created": 1790310999, "data": [{"url": "https://cdn.example.com/media/tasks/task_example/0.jpg"}], "output_format": "jpeg", "usage": { "input_tokens": 27, "output_tokens": 1518, "total_tokens": 1545, "output_tokens_details": {"image_tokens": 1120, "text_tokens": 398, "reasoning_tokens": 0} } } } ``` | Field | Meaning | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Keep this ID for subsequent queries. | | `status` | `processing`, `completed`, or `failed`. | | `created_at`, `finished_at` | Unix timestamps in seconds. | | `output.data[].url` | The generated image URL. | | `output.text` | Text the model returned alongside the image, when `responseModalities` includes `TEXT`. Thoughts are not included. | | `output.thoughts` | The model's thought summaries, when `includeThoughts` is `true`. Interim images the model draws while thinking are not delivered. | | `output.output_format` | Actual image format. | | `output.parts` | The final response parts in order, for multi-turn editing: `{"text", "thoughtSignature"}` or `{"image": , "thoughtSignature"}`. `thoughtSignature` is a URL; send it back unchanged. | | `output.usage` | Token usage. `output_tokens` counts text, thinking, and image output; `output_tokens_details.image_tokens` is the image part. | | `error` | Structured error on a failed task. | Streaming (`streamGenerateContent`) is not supported; results are delivered through the task. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. An image withheld by the model's safety filters fails with `content_policy_violation`; a response with no image fails with `no_output`. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your task history before submitting again: the first request may have been accepted. ## Tips * Describe subject, setting, lighting, and style in full sentences. * For an edit, say what should change and what must stay the same. * Choose Nano Banana 2 or Nano Banana Pro when you need 2K or 4K output. * Save returned images to your own storage when you need a durable copy. ## Related * [Nano Banana 2 Lite pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gemini-3-1-flash-lite-image.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gemini-3-1-flash-lite-image.md) --- Source: https://toklab.ai/docs/gemini-3-1-pro Use `gemini-3.1-pro-preview` with the native Gemini format. Current prices are on the [pricing page](https://toklab.ai/pricing). ## Model ID | Model ID | Input limit | Default effort | | ------------------------ | ---------------- | -------------- | | `gemini-3.1-pro-preview` | 1,048,576 tokens | `high` | ## Quick example ```bash curl https://api.toklab.ai/v1beta/models/gemini-3.1-pro-preview:generateContent \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"contents":[{"role":"user","parts":[{"text":"Explain a mutex in one sentence."}]}],"generationConfig":{"thinkingConfig":{"thinkingLevel":"low"},"maxOutputTokens":1024}}' ``` ```python import json import os from urllib.request import Request, urlopen body = { "contents": [{"role": "user", "parts": [{"text": "Explain a mutex in one sentence."}]}], "generationConfig": {"thinkingConfig": {"thinkingLevel": "low"}, "maxOutputTokens": 1024}, } request = Request( "https://api.toklab.ai/v1beta/models/gemini-3.1-pro-preview:generateContent", data=json.dumps(body).encode(), headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}", "Content-Type": "application/json"}, method="POST", ) with urlopen(request) as response: print(json.load(response)) ``` ```javascript const response = await fetch( "https://api.toklab.ai/v1beta/models/gemini-3.1-pro-preview:generateContent", { method: "POST", headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ contents: [{ role: "user", parts: [{ text: "Explain a mutex in one sentence." }] }], generationConfig: { thinkingConfig: { thinkingLevel: "low" }, maxOutputTokens: 1024 }, }), }, ); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"contents":[{"role":"user","parts":[{"text":"Explain a mutex in one sentence."}]}],"generationConfig":{"thinkingConfig":{"thinkingLevel":"low"},"maxOutputTokens":1024}}`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1beta/models/gemini-3.1-pro-preview:generateContent", bytes.NewReader(body)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, err := io.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Println(string(out)) } ``` The model belongs in the URL. `contents` is required. An answer includes native `candidates`, `finishReason` and `usageMetadata`; retain complete content parts, including `thoughtSignature`, for conversation history. ## Endpoints | Operation | Endpoint | | ------------------ | -------------------------------------------------------------------------- | | JSON response | `POST /v1beta/models/gemini-3.1-pro-preview:generateContent` | | Server-sent events | `POST /v1beta/models/gemini-3.1-pro-preview:streamGenerateContent?alt=sse` | The [OpenAPI specification](https://toklab.ai/docs/gemini-3-1-pro.openapi.json) includes every nested request and response schema. Optional fields use API defaults when omitted. TokLab forwards the submitted body without filtering unknown fields, removing unsupported fields or validating model parameter values. The Gemini API decides whether a request is accepted. ## Request parameters The URL fixes the model to `gemini-3.1-pro-preview`. The request contract contains 12 top-level fields. Fields are optional unless marked required; omission differs from JSON `null`. Nullable arbitrary JSON is preserved where the official schema permits it. | Field | Type | Required | Default and constraints | | ------------------- | --------- | -------- | ------------------------------------------------------------------------------ | | `contents` | object\[] | Yes | Nonempty conversation; each content has nonempty `parts` | | `systemInstruction` | object | No | Text-only parts; no automatic user identity is inserted | | `generationConfig` | object | No | Generation parameters in the next table | | `tools` | object\[] | No | Function declarations and built-in tool configurations | | `toolConfig` | object | No | Function selection and retrieval configuration | | `safetySettings` | object\[] | No | One setting per category; no duplicate categories | | `cachedContent` | string | No | Existing `cachedContents/{id}` resource; requires compatible access | | `serviceTier` | string | No | `unspecified`, `standard`, `flex`, `priority`; ordinary processing is standard | | `labels` | object | No | String values; lowercase keys/values, maximum 63 Unicode codepoints each | | `model` | string | No | Optional resource name; the URL determines the actual model | | `store` | boolean | No | Generic request storage preference; model-specific effect unverified | | `continuationToken` | string | No | Generic opaque token; continuation is not an established 3.1 Pro capability | ### Generation parameters | Field in `generationConfig` | Type | Default and constraints | | ---------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `maxOutputTokens` | integer | 1–65,536, including thinking; model default 65,536 | | `thinkingConfig` | object | `thinkingLevel`: `low`, `medium`, `high` (default `high`); uppercase spellings accepted. `includeThoughts`: boolean, default false. `thinkingBudget`: integer, mutually exclusive with `thinkingLevel`; no model-specific numeric range is established | | `temperature` | number | 0–2; Google recommends the default 1.0 | | `topP` | number | 0–1; omit to use the model default | | `topK` | integer | Optional; model-specific configurable range not established | | `candidateCount` | integer | Exactly 1 | | `stopSequences` | string\[] | Maximum five sequences | | `responseMimeType` | string | Default `text/plain`; legacy JSON schema output requires `application/json` | | `responseSchema` | object | Official schema dialect; mutually exclusive with `responseJsonSchema` | | `responseJsonSchema` | JSON | JSON Schema; mutually exclusive with `responseSchema` | | `responseFormat` | object | Text format configuration; `text.mimeType` and optional `text.schema`. Schema requires JSON MIME type | | `responseModalities` | string\[] | Text only: `TEXT`; empty means text | | `mediaResolution` | enum | `MEDIA_RESOLUTION_UNSPECIFIED`, `LOW`, `MEDIUM`, `HIGH` with the `MEDIA_RESOLUTION_` prefix | | `seed` | integer | Signed 32-bit value; model-specific deterministic behavior unverified | | `presencePenalty` | number | Generic field; model-specific effect/range unverified | | `frequencyPenalty` | number | Generic field; model-specific effect/range unverified | | `responseLogprobs` | boolean | Generic field; model-specific availability unverified | | `logprobs` | integer | 0–20; requires `responseLogprobs: true`; model support unverified | | `enableEnhancedCivicAnswers` | boolean | Generic field; model support unverified | | `enableAffectiveDialog` | boolean | Generic field; model support unverified | | `audioTranscriptionConfig` | object | Generic field; model-specific options unverified | | `translationConfig` | object | Generic field; model-specific options unverified | The [OpenAPI document](https://toklab.ai/docs/gemini-3-1-pro.openapi.json) lists nested types, enums, required properties and documented bounds for every message. The schemas describe official parameters; they are not a TokLab request allowlist. Caller-supplied fields and values are preserved. A field accepted by the schema is not proof of support for every model or account. `minimal` thinking and Agentic Video processing are not supported by this model. ## Structured output ```json { "contents": [{"parts": [{"text": "Return a JSON object with ok set to true."}]}], "generationConfig": { "thinkingConfig": {"thinkingLevel": "low"}, "maxOutputTokens": 1024, "responseMimeType": "application/json", "responseJsonSchema": { "type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"] } } } ``` The legacy `responseSchema` and `responseJsonSchema` fields cannot be used together. Both require `responseMimeType: "application/json"`. The newer `responseFormat.text` schema must likewise specify JSON. Use REST enum spellings (`APPLICATION_JSON` and `TEXT_PLAIN`) in that message. Requests pass through unchanged; media MIME types and arbitrary function JSON are not rewritten. ## Functions and built-in tools Use `tools[].functionDeclarations` with a name and either `parameters` or `parametersJsonSchema`, not both. Response schemas follow the same mutual-exclusion rule. Function selection lives in `toolConfig.functionCallingConfig`; `allowedFunctionNames` requires `ANY` or `VALIDATED` and declared names. The regular model supports function calling; the customtools variant is not required. Your application executes returned functions and supplies their results in the next conversation turn. Preserve each original `thoughtSignature`, function call and function response. Do not round numeric identifiers when serializing opaque function arguments. Google lists Search, Maps, code execution and URL context as model capabilities. File Search is listed for AI Studio only. Existing cache and file-search resources require access under the credentials serving the request. Computer Use and native MCP configuration appear in the generic schema but their availability for this model is not established. ## Multimodal input and safety A `contents[].parts[]` item contains exactly one payload: text, inline media, a file reference, a function call/response, or an execution part. It may also carry a signature or media metadata. Input supports text, images, audio, video and PDFs; output is text only. For inline bytes, use `inlineData.mimeType` and base64 `data`. For file references, use `fileData.mimeType` and `fileUri`. A syntactically valid URL is not proof the model can retrieve it. Video metadata can specify start/end offsets and a positive `fps` no greater than 24. Global and per-part media resolutions are distinct settings. Agentic Video is not supported. Use native JSON for inline media, or an accessible file reference for larger media. Exact file-format, duration and per-request media limits remain subject to the official media documentation and live verification. Safety settings use the official native format. Omission leaves the Gemini API defaults in effect; explicitly supplied settings pass through unchanged. ## JSON responses and streaming `generateContent` returns native JSON. `streamGenerateContent?alt=sse` emits native JSON in SSE `data:` events. Important fields include `candidates[].content.parts`, `finishReason`, `safetyRatings`, `groundingMetadata`, `promptFeedback`, `modelVersion`, `responseId` and `usageMetadata`. Retain complete native content in conversation history. Thinking summaries are not the same as thought signatures. A disconnect does not prove generation failed or completed; inspect the partial result and account record before sending another request. Stream usage is cumulative, so use the latest counters instead of summing every chunk. Unlike Argon, longer-output continuation has not been established for 3.1 Pro. Do not build a continuation loop merely because the generic response schema includes a token field. ## Usage and pricing `promptTokenCount` includes cached input. `cachedContentTokenCount` is charged at the cached-input rate, rather than charged again as uncached input. Billable output includes `candidatesTokenCount` plus `thoughtsTokenCount`. Reported tool-use prompt tokens also contribute to input. The context threshold is 200,000 input tokens, including cached input; larger inputs use the long-context rates. Available account groups use the same model price expression and their own current multiplier. See the [live pricing table](https://toklab.ai/pricing). Flex and Priority are separate processing tiers. Flex does not halve cached-input rates. A reported Standard result must not incur a Priority surcharge. If a requested Priority response does not establish its actual tier, this integration uses Standard token rates. Tool charges and explicit cache storage are separate from generation-token pricing; no shared free tool allowance is promised. Failed requests are not charged. ## Multiple account groups The model uses `googlellm` and `googlellm-vertext`, retaining their existing account permissions and pricing. The spelling of each group name is exact. Select one with the optional API header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)): ```http X-SeedRouter-Group: googlellm ``` Use `googlellm-vertext` to select the second group. The chosen group determines the price and available capacity; an explicit selection does not silently switch to another group. Omit the header or use `auto` to keep the API key's default behavior. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. ## Verification status The controls and documentation follow the official native format. Parameter validation belongs to the Gemini API. Offline transport and billing checks do not establish production availability. Live generation, both account groups, media understanding, cached resources, built-in tools and processing tiers still require paid end-to-end verification. No comparative quality result is claimed for the Customtools variant. ## References * [Google model specification](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-pro-preview) * [Native Gemini 3 guide](https://ai.google.dev/gemini-api/docs/generate-content/gemini-3) * [GenerateContent REST reference](https://ai.google.dev/api/generate-content) * [Structured output](https://ai.google.dev/gemini-api/docs/generate-content/structured-output) * [Thinking](https://ai.google.dev/gemini-api/docs/generate-content/thinking) * [Pricing](https://ai.google.dev/gemini-api/docs/pricing) --- Source: https://toklab.ai/docs/gemini-3-8-flash Use `gemini-3.8-flash` with the native Gemini format. Current prices are on the [pricing page](https://toklab.ai/pricing). ## Model ID | Model ID | Input limit | Default effort | | ------------------ | ---------------- | -------------- | | `gemini-3.8-flash` | 1,048,576 tokens | `medium` | ## Quick example ```bash curl https://api.toklab.ai/v1beta/models/gemini-3.8-flash:generateContent \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"contents":[{"role":"user","parts":[{"text":"Explain a mutex in one sentence."}]}],"generationConfig":{"thinkingConfig":{"thinkingLevel":"low"},"maxOutputTokens":1024}}' ``` ```python import json import os from urllib.request import Request, urlopen body = { "contents": [{"role": "user", "parts": [{"text": "Explain a mutex in one sentence."}]}], "generationConfig": {"thinkingConfig": {"thinkingLevel": "low"}, "maxOutputTokens": 1024}, } request = Request( "https://api.toklab.ai/v1beta/models/gemini-3.8-flash:generateContent", data=json.dumps(body).encode(), headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}", "Content-Type": "application/json"}, method="POST", ) with urlopen(request) as response: print(json.load(response)) ``` ```javascript const response = await fetch( "https://api.toklab.ai/v1beta/models/gemini-3.8-flash:generateContent", { method: "POST", headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ contents: [{ role: "user", parts: [{ text: "Explain a mutex in one sentence." }] }], generationConfig: { thinkingConfig: { thinkingLevel: "low" }, maxOutputTokens: 1024 }, }), }, ); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"contents":[{"role":"user","parts":[{"text":"Explain a mutex in one sentence."}]}],"generationConfig":{"thinkingConfig":{"thinkingLevel":"low"},"maxOutputTokens":1024}}`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1beta/models/gemini-3.8-flash:generateContent", bytes.NewReader(body)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, err := io.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Println(string(out)) } ``` The model belongs in the URL. `contents` is required. An answer includes native `candidates`, `finishReason` and `usageMetadata`; retain complete content parts, including `thoughtSignature`, for conversation history. ## Endpoints | Operation | Endpoint | | ------------------ | -------------------------------------------------------------------- | | JSON response | `POST /v1beta/models/gemini-3.8-flash:generateContent` | | Server-sent events | `POST /v1beta/models/gemini-3.8-flash:streamGenerateContent?alt=sse` | The [OpenAPI specification](https://toklab.ai/docs/gemini-3-8-flash.openapi.json) includes every nested request and response schema. Optional fields use API defaults when omitted. TokLab forwards the submitted body without filtering unknown fields, removing unsupported fields or validating model parameter values. The Gemini API decides whether a request is accepted. ## Request parameters The URL fixes the model to `gemini-3.8-flash`. The request contract contains 12 top-level fields. Fields are optional unless marked required; omission differs from JSON `null`. Nullable arbitrary JSON is preserved where the official schema permits it. | Field | Type | Required | Default and constraints | | ------------------- | --------- | -------- | ------------------------------------------------------------------------------ | | `contents` | object\[] | Yes | Nonempty conversation; each content has nonempty `parts` | | `systemInstruction` | object | No | Text-only parts; no automatic user identity is inserted | | `generationConfig` | object | No | Generation parameters in the next table | | `tools` | object\[] | No | Function declarations and built-in tool configurations | | `toolConfig` | object | No | Function selection and retrieval configuration | | `safetySettings` | object\[] | No | One setting per category; no duplicate categories | | `cachedContent` | string | No | Existing `cachedContents/{id}` resource; requires compatible access | | `serviceTier` | string | No | `unspecified`, `standard`, `flex`, `priority`; ordinary processing is standard | | `labels` | object | No | String values; lowercase keys/values, maximum 63 Unicode codepoints each | | `model` | string | No | Optional resource name; the URL determines the actual model | | `store` | boolean | No | Generic request storage preference; model-specific effect unverified | | `continuationToken` | string | No | Generic opaque token; continuation is not an established 3.8 Flash capability | ### Generation parameters | Field in `generationConfig` | Type | Default and constraints | | ---------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `maxOutputTokens` | integer | 1–65,536, including thinking; model default 65,536 | | `thinkingConfig` | object | `thinkingLevel`: `low`, `medium`, `high` (default `medium`); uppercase spellings accepted. `includeThoughts`: boolean, default false. `thinkingBudget`: integer, mutually exclusive with `thinkingLevel`; no model-specific numeric range is established | | `stopSequences` | string\[] | Maximum five sequences | | `responseMimeType` | string | Default `text/plain`; legacy JSON schema output requires `application/json` | | `responseSchema` | object | Official schema dialect; mutually exclusive with `responseJsonSchema` | | `responseJsonSchema` | JSON | JSON Schema; mutually exclusive with `responseSchema` | | `responseFormat` | object | Text format configuration; `text.mimeType` and optional `text.schema`. Schema requires JSON MIME type | | `responseModalities` | string\[] | Text only: `TEXT`; empty means text | | `mediaResolution` | enum | `MEDIA_RESOLUTION_UNSPECIFIED`, `LOW`, `MEDIUM`, `HIGH` with the `MEDIA_RESOLUTION_` prefix | | `seed` | integer | Signed 32-bit value; model-specific deterministic behavior unverified | | `presencePenalty` | number | Generic field; model-specific effect/range unverified | | `frequencyPenalty` | number | Generic field; model-specific effect/range unverified | | `responseLogprobs` | boolean | Generic field; model-specific availability unverified | | `logprobs` | integer | 0–20; requires `responseLogprobs: true`; model support unverified | | `enableEnhancedCivicAnswers` | boolean | Generic field; model support unverified | | `enableAffectiveDialog` | boolean | Generic field; model support unverified | | `audioTranscriptionConfig` | object | Generic field; model-specific options unverified | | `translationConfig` | object | Generic field; model-specific options unverified | The [OpenAPI document](https://toklab.ai/docs/gemini-3-8-flash.openapi.json) lists nested types, enums, required properties and documented bounds for every message. The schemas describe official parameters; they are not a TokLab request allowlist. Caller-supplied fields and values are preserved. A field accepted by the schema is not proof of support for every model or account. `minimal` thinking is not supported. Temperature, topP, topK and candidateCount are not official controls for this model. If submitted in native JSON, they still pass through unchanged for the Gemini API to handle. End the conversation with user content; the official API does not support final model-prefill turns. Function-response-only user turns remain valid. ## Structured output ```json { "contents": [{"parts": [{"text": "Return a JSON object with ok set to true."}]}], "generationConfig": { "thinkingConfig": {"thinkingLevel": "low"}, "maxOutputTokens": 1024, "responseMimeType": "application/json", "responseJsonSchema": { "type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"] } } } ``` The legacy `responseSchema` and `responseJsonSchema` fields cannot be used together. Both require `responseMimeType: "application/json"`. The newer `responseFormat.text` schema must likewise specify JSON. Use REST enum spellings (`APPLICATION_JSON` and `TEXT_PLAIN`) in that message. Requests pass through unchanged; media MIME types and arbitrary function JSON are not rewritten. ## Functions and built-in tools Use `tools[].functionDeclarations` with a name and either `parameters` or `parametersJsonSchema`, not both. Response schemas follow the same mutual-exclusion rule. Function selection lives in `toolConfig.functionCallingConfig`; `allowedFunctionNames` requires `ANY` or `VALIDATED` and declared names. The model supports function calling. Your application executes returned functions and supplies their results in the next conversation turn. Preserve each original `thoughtSignature`, function call and function response. Do not round numeric identifiers when serializing opaque function arguments. Google lists Search, Maps, code execution and URL context as model capabilities. File Search is supported in the model documentation. Existing cache and file-search resources require access under the credentials serving the request. Computer Use is listed as Preview. Native MCP configuration appears in the generic schema, but its availability for this model is not established. Google Maps requires text-only input and output; check the official API restrictions before combining Maps with media. ## Multimodal input and safety A `contents[].parts[]` item contains exactly one payload: text, inline media, a file reference, a function call/response, or an execution part. It may also carry a signature or media metadata. Input supports text, images, audio, video and PDFs; output is text only. For inline bytes, use `inlineData.mimeType` and base64 `data`. For file references, use `fileData.mimeType` and `fileUri`. A syntactically valid URL is not proof the model can retrieve it. Video metadata can specify start/end offsets and a positive `fps` no greater than 24. Global and per-part media resolutions are distinct settings. Agentic Video is supported through `videoMetadata.processingMode: "AGENTIC"`. Use native JSON for inline media, or an accessible file reference for larger media. Exact file-format, duration and per-request media limits remain subject to the official media documentation and live verification. Safety settings use the official native format. Omission leaves the Gemini API defaults in effect; explicitly supplied settings pass through unchanged. ## JSON responses and streaming `generateContent` returns native JSON. `streamGenerateContent?alt=sse` emits native JSON in SSE `data:` events. Important fields include `candidates[].content.parts`, `finishReason`, `safetyRatings`, `groundingMetadata`, `promptFeedback`, `modelVersion`, `responseId` and `usageMetadata`. Retain complete native content in conversation history. Thinking summaries are not the same as thought signatures. A disconnect does not prove generation failed or completed; inspect the partial result and account record before sending another request. Stream usage is cumulative, so use the latest counters instead of summing every chunk. Longer-output continuation has not been established for Gemini 3.8 Flash. Do not build a continuation loop merely because the generic response schema includes a token field. ## Usage and pricing `promptTokenCount` includes cached input. `cachedContentTokenCount` is charged at the cached-input rate, rather than charged again as uncached input. Billable output includes `candidatesTokenCount` plus `thoughtsTokenCount`. Reported tool-use prompt tokens also contribute to input. There is no 200,000-token long-context price step for this model. Available account groups use the same model price expression and their own current multiplier. See the [live pricing table](https://toklab.ai/pricing). Flex and Priority are separate processing tiers. Flex uses half of Standard input, output and cached-input rates; Priority uses 1.8 times those rates. Published introductory Google rates end December 31, 2026; always check the current TokLab table rather than assuming a future rate. A reported Standard result must not incur a Priority surcharge. If a requested Priority response does not establish its actual tier, this integration uses Standard token rates. Tool charges and explicit cache storage are separate from generation-token pricing; no shared free tool allowance is promised. Failed requests are not charged. ## Multiple account groups The model uses `googlellm` and `googlellm-vertext`, retaining their existing account permissions and pricing. The spelling of each group name is exact. Select one with the optional API header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)): ```http X-SeedRouter-Group: googlellm ``` Use `googlellm-vertext` to select the second group. The chosen group determines the price and available capacity; an explicit selection does not silently switch to another group. Omit the header or use `auto` to keep the API key's default behavior. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. ## Verification status The controls and documentation follow the official native format. Parameter validation belongs to the Gemini API. Offline transport and billing checks do not establish production availability. Live generation, both account groups, media understanding, cached resources, built-in tools and processing tiers still require paid end-to-end verification. No measured quality or latency comparison with Gemini 3.1 Pro is claimed. ## References * [Google model specification](https://ai.google.dev/gemini-api/docs/models/gemini-3.8-flash) * [Gemini 3.8 changes](https://ai.google.dev/gemini-api/docs/generate-content/whats-new-gemini-3.8) * [GenerateContent REST reference](https://ai.google.dev/api/generate-content) * [Structured output](https://ai.google.dev/gemini-api/docs/generate-content/structured-output) * [Thinking](https://ai.google.dev/gemini-api/docs/generate-content/thinking) * [Pricing](https://ai.google.dev/gemini-api/docs/pricing) --- Source: https://toklab.ai/docs/gemini-3-pro-image Nano Banana Pro is Google's Gemini 3 Pro Image model, built for professional assets and complex instructions. It thinks before it draws, so responses report reasoning tokens. Send Google's `generateContent` request body with a `model` field, keep the returned task ID, and check that task for the finished image. Reference images go in `contents` as `fileData` URLs. ## Model IDs | Model ID | Channel | Billing | | ----------------------------- | -------- | ---------------------------------------------------------------- | | `gemini-3-pro-image` | Standard | One flat price per delivered image | | `gemini-3-pro-image-official` | Official | Per-token rates for input, text/thinking output and image output | Both IDs accept the same parameters. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-pro-image", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gemini-3-pro-image", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"}, }, }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gemini-3-pro-image', contents: [{ parts: [{ text: 'A ceramic teapot on a linen tablecloth, soft window light' }] }], generationConfig: { responseModalities: ['IMAGE'], imageConfig: { aspectRatio: '16:9', imageSize: '2K' }, }, }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gemini-3-pro-image", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The body is Google's `generateContent` request with one addition: `model`, because this endpoint carries no model in its path. The response contains a task ID, not the finished image. Keep API keys in server-side code. Calling `/v1beta/models/...:generateContent` directly is not supported; use this endpoint. ## Parameters | Name | Type | Required | Default | Notes | | ------------------------------------------------- | ---------- | -------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | One of the two model IDs above. | | `contents` | Content\[] | Yes | — | 1–32 turns. Each has `parts` and an optional `role` (`user` or `model`); the last turn is `user`. | | `contents[].parts[].text` | string | — | — | A text part. At least one text part is required. | | `contents[].parts[].fileData` | object | No | — | `{"mimeType": "...", "fileUri": "https://..."}`; a reference image. Up to 14 in total. | | `systemInstruction` | object | No | — | `{"parts": [{"text": "..."}]}`. | | `safetySettings` | object\[] | No | — | `{"category", "threshold"}` pairs; see below. | | `generationConfig.responseModalities` | enum\[] | No | text and image | `["IMAGE"]` for images only, or `["TEXT", "IMAGE"]`. | | `generationConfig.imageConfig.aspectRatio` | enum | No | Input image ratio, else `1:1` | `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`. | | `generationConfig.imageConfig.imageSize` | enum | No | `1K` | `1K`, `2K`, `4K`. Uppercase `K`. | | `generationConfig.candidateCount` | integer | No | `1` | Only `1`. One request returns one image. | | `generationConfig.temperature` | number | No | Model default | 0–2. | | `generationConfig.topP` | number | No | Model default | 0–1. | | `generationConfig.topK` | integer | No | Model default | 1 or more. | | `generationConfig.seed` | integer | No | — | 32-bit integer. | | `generationConfig.maxOutputTokens` | integer | No | Model default | 1–32,768. | | `generationConfig.stopSequences` | string\[] | No | — | Up to 5. | | `generationConfig.mediaResolution` | enum | No | Model default | `MEDIA_RESOLUTION_LOW`, `MEDIA_RESOLUTION_MEDIUM`, `MEDIA_RESOLUTION_HIGH`. Sets how many tokens input media use. | | `generationConfig.thinkingConfig.includeThoughts` | boolean | No | `false` | Return the model's thought summaries as `output.thoughts`. | | `generationConfig.responseFormat.image` | object | No | — | `mimeType`: `IMAGE_JPEG`; `delivery`: `INLINE`; `aspectRatio` and `imageSize` as Google's enums, e.g. `ASPECT_RATIO_SIXTEEN_BY_NINE` and `IMAGE_SIZE_TWO_K`, covering the same ratios and sizes as `imageConfig`. Not accepted by `gemini-3-pro-image-official`. | Safety categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`, `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`. Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`, `BLOCK_LOW_AND_ABOVE`, `OFF`. Unknown fields are rejected. Not yet available: Google Search grounding (`tools`) and cached content; `thinkingLevel` is not documented for this model. `inlineData` is not accepted; pass media as `fileData` URLs. `responseFormat.image.delivery` accepts only `INLINE`: finished images are always returned as hosted URLs. ### Output size | `imageSize` | 1:1 output | Image tokens | | ----------- | ---------- | ------------ | | `1K` | 1024×1024 | 1,120 | | `2K` | 2048×2048 | 1,120 | | `4K` | 4096×4096 | 2,000 | Other aspect ratios keep the same token count; for example `16:9` at `1K` is 1376×768. ## Modes There is no separate mode parameter or editing endpoint. | Operation | Parameters | | --------------- | ----------------------------------------------------------------------------- | | Text to image | a text part | | Edit or compose | text part + one or more `fileData` parts | | Multi-turn edit | earlier `user` and `model` turns, then a new `user` turn (see the note below) | To continue a conversation, rebuild the `model` turn from the previous task's `output.parts`, in order: a text part becomes `{"text": ..., "thoughtSignature": ...}` and an image part becomes `{"fileData": {"mimeType": "image/", "fileUri": }, "thoughtSignature": ...}`. Keep each `thoughtSignature` exactly as returned: it is the URL of the signature we stored for you (a 4K image's signature is several megabytes), and we restore it before the request reaches the model. Only signatures from your own task results are accepted. ### Edit with a reference image ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-pro-image", "contents": [{ "role": "user", "parts": [ {"text": "Turn this photo into a watercolor painting. Keep the composition."}, {"fileData": {"mimeType": "image/jpeg", "fileUri": "https://example.com/photo.jpg"}} ] }] }' ``` Replace the example URL with your own accessible image. ## Media inputs This API accepts URL references only. Base64 `inlineData`, `data:` URLs, and multipart uploads are not accepted. Reference images must be public HTTP(S) URLs to PNG, JPEG, WebP, HEIC, or HEIF files, each smaller than 50 MB and 100 MB in total. `mimeType` must match the file. URLs are fetched during processing; an inaccessible image fails the task, and a failed task is not charged. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. `gemini-3-pro-image` charges one flat price per delivered image, whatever the size or prompt. `gemini-3-pro-image-official` charges by usage: input tokens (text and reference images), text and thinking output tokens, and image output tokens, each at its own rate. The image size is the main factor; see the table above. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns a task reference: ```json { "id": "task_...", "model": "gemini-3-pro-image", "status": "processing", "created_at": 1790310979 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Poll every few seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Complete polling example Run this after the Python submission example above. ```python import time deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task ```json { "id": "task_...", "model": "gemini-3-pro-image", "status": "completed", "created_at": 1790310979, "finished_at": 1790311001, "output": { "created": 1790310999, "data": [{"url": "https://cdn.example.com/media/tasks/task_example/0.jpg"}], "output_format": "jpeg", "usage": { "input_tokens": 27, "output_tokens": 1366, "total_tokens": 1393, "output_tokens_details": {"image_tokens": 1120, "text_tokens": 95, "reasoning_tokens": 151} } } } ``` | Field | Meaning | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Keep this ID for subsequent queries. | | `status` | `processing`, `completed`, or `failed`. | | `created_at`, `finished_at` | Unix timestamps in seconds. | | `output.data[].url` | The generated image URL. | | `output.text` | Text the model returned alongside the image, when `responseModalities` includes `TEXT`. Thoughts are not included. | | `output.thoughts` | The model's thought summaries, when `includeThoughts` is `true`. Interim images the model draws while thinking are not delivered. | | `output.output_format` | Actual image format. | | `output.parts` | The final response parts in order, for multi-turn editing: `{"text", "thoughtSignature"}` or `{"image": , "thoughtSignature"}`. `thoughtSignature` is a URL; send it back unchanged. | | `output.usage` | Token usage. `output_tokens` counts text, thinking, and image output; `output_tokens_details.image_tokens` is the image part. | | `error` | Structured error on a failed task. | Streaming (`streamGenerateContent`) is not supported; results are delivered through the task. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. An image withheld by the model's safety filters fails with `content_policy_violation`; a response with no image fails with `no_output`. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your task history before submitting again: the first request may have been accepted. ## Tips * Describe subject, setting, lighting, and style in full sentences. * For an edit, say what should change and what must stay the same. * `2K` costs the same image tokens as `1K`; use `4K` for print-sized assets. * Save returned images to your own storage when you need a durable copy. ## Related * [Nano Banana Pro pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gemini-3-pro-image.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gemini-3-pro-image.md) --- Source: https://toklab.ai/docs/gemini-4-argon Use `gemini-4-argon` with the native Gemini format. Current prices are on the [pricing page](https://toklab.ai/pricing). ## Model ID | Model ID | Context window | Default effort | | ---------------- | ---------------- | -------------- | | `gemini-4-argon` | 1,048,576 tokens | `medium` | ## Quick example ```bash curl https://api.toklab.ai/v1beta/models/gemini-4-argon:generateContent \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"contents":[{"role":"user","parts":[{"text":"Explain a mutex in one sentence."}]}],"generationConfig":{"thinkingConfig":{"thinkingLevel":"low"},"maxOutputTokens":256}}' ``` ```python import json import os from urllib.request import Request, urlopen body = { "contents": [{"role": "user", "parts": [{"text": "Explain a mutex in one sentence."}]}], "generationConfig": {"thinkingConfig": {"thinkingLevel": "low"}, "maxOutputTokens": 256}, } request = Request( "https://api.toklab.ai/v1beta/models/gemini-4-argon:generateContent", data=json.dumps(body).encode(), headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}", "Content-Type": "application/json"}, method="POST", ) with urlopen(request) as response: print(json.load(response)) ``` ```javascript const response = await fetch( "https://api.toklab.ai/v1beta/models/gemini-4-argon:generateContent", { method: "POST", headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ contents: [{ role: "user", parts: [{ text: "Explain a mutex in one sentence." }] }], generationConfig: { thinkingConfig: { thinkingLevel: "low" }, maxOutputTokens: 256 }, }), }, ); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"contents":[{"role":"user","parts":[{"text":"Explain a mutex in one sentence."}]}],"generationConfig":{"thinkingConfig":{"thinkingLevel":"low"},"maxOutputTokens":256}}`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1beta/models/gemini-4-argon:generateContent", bytes.NewReader(body)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, err := io.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Println(string(out)) } ``` The model belongs in the URL. `contents` is required. An answer includes native `candidates`, `finishReason` and `usageMetadata`; retain complete content parts, including `thoughtSignature`, for conversation history. ## Endpoints | Operation | Endpoint | | ------------------ | ------------------------------------------------------------------ | | JSON response | `POST /v1beta/models/gemini-4-argon:generateContent` | | Server-sent events | `POST /v1beta/models/gemini-4-argon:streamGenerateContent?alt=sse` | The [OpenAPI specification](https://toklab.ai/docs/gemini-4-argon.openapi.json) includes every nested request and response schema. Optional fields use API defaults when omitted. Unknown and officially unsupported fields are discarded; invalid values of supported fields remain errors. ## Parameters | Name | Type | Required | Default | Notes | | ------------------- | --------- | -------- | ---------- | -------------------------------------------------------------------------- | | `contents` | object\[] | Yes | — | Required conversation array; `parts` carries text, media and tool results | | `systemInstruction` | object | No | — | Text-only system instruction | | `generationConfig` | object | No | — | Output budget, thinking, structured output, stopping and media settings | | `tools` | object\[] | No | — | Functions and built-in tool definitions | | `toolConfig` | object | No | — | Function selection, retrieval settings and server tool parts | | `safetySettings` | object\[] | No | — | Unique category and threshold pairs | | `continuationToken` | string | No | — | Opaque continuation token from the latest candidate | | `serviceTier` | enum | No | `standard` | `unspecified`, `standard`, `flex`, `priority`; standard by default | | `labels` | object | No | — | Lowercase label keys and values, up to 63 Unicode characters each | | `store` | boolean | No | — | Request logging preference; does not provide stored conversation retrieval | | `model` | string | No | — | Optional body resource name; the URL fixes the model | `generationConfig` includes `maxOutputTokens`, `thinkingConfig`, `stopSequences`, `responseFormat`, legacy `responseMimeType`/`responseSchema`/`responseJsonSchema`, `responseModalities`, `mediaResolution`, `seed`, `presencePenalty`, `frequencyPenalty`, `responseLogprobs`, `logprobs`, `enableEnhancedCivicAnswers`, `enableAffectiveDialog`, `translationConfig` and `audioTranscriptionConfig`. Generic fields without confirmed model-specific behavior remain subject to capability verification. * Thinking levels: `low`, `medium`, `high`; default `medium`. Thinking cannot be disabled. `includeThoughts` requests summaries. Deprecated `thinkingBudget` is accepted alone, but cannot be combined with `thinkingLevel`. * Input, thinking and output share 1,048,576 tokens. `maxOutputTokens` includes thinking; the remaining context may reduce the effective budget. * Native REST uses a per-request output ceiling/default of 32,768 tokens, or 65,536 when streaming. Longer output uses continuation. Official documentation conflicts on first non-streaming requests above 32,768; this integration does not impose that as a total-generation limit. * At most five `stopSequences`. `logprobs` ranges from 0 to 20 and requires `responseLogprobs: true`. * `responseSchema` and `responseJsonSchema` are mutually exclusive and require `responseMimeType: "application/json"`. New requests can use `responseFormat.text` below. * `responseModalities` can contain `TEXT` only. Temperature, top-p, top-k and candidate count are not active Argon controls. Explicit `cachedContent`, image generation and speech generation are unsupported. ## Structured output and tools ```json { "contents": [{"parts": [{"text": "Return a JSON object with ok set to true."}]}], "generationConfig": { "thinkingConfig": {"thinkingLevel": "low"}, "maxOutputTokens": 256, "responseFormat": { "text": { "mimeType": "APPLICATION_JSON", "schema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]} } } } } ``` Functions use `tools[].functionDeclarations`. `allowedFunctionNames` requires mode `ANY` or `VALIDATED` and declared names. Keep function calls, responses and signatures in their original order. Google Search, Maps, code execution, URL context, File Search and Computer Use are official capabilities; resource access, charges and behavior must be verified for your intended operation. ## Media and safety Native `parts` accepts text, image, audio, video and PDF inputs through `inlineData` or `fileData`. A part contains one payload variant, optionally accompanied by thought signatures and media metadata. Global `mediaResolution` and per-part resolution are distinct. Video supports `STATIC` and `AGENTIC` processing; `videoMetadata.fps` is greater than zero and at most 24. This is an application transport limit, not the model’s media limit. For large media, use file references supported by your account. File resources and externally fetched media have different official limits; their availability has not yet been verified here. Public API safety settings follow the native contract. ## Streaming and continuation Read native JSON events from the SSE stream. Keep all parts, including tool and thinking metadata. Usage counters within one stream are cumulative: use the last usage object rather than adding every event. When a candidate returns `continuationToken`, preserve it exactly. For `CONTINUATION`, resend the original contents, system instruction, tools and generation settings with the latest token at the **top level**. Do not append partial output to contents. For `MAX_TOKENS`, increase the output budget before resuming. Each continuation is a separate request with its own usage and charge. Keep checkpoints if you implement reconnects; never assume a disconnected stream completed. ## Usage and current verification status Input usage includes cached input; billable output includes candidate and thinking tokens. Consult the current model-page rates and your account usage records. Failed requests are not charged. Local checks on October 14, 2026 verified text streaming, structured JSON, signed function-call round trips, code execution, Google Search and URL context, image/video/PDF understanding, thinking output and stop sequences. Audio was accepted but part of the sample was transcribed incorrectly. `logprobs` was explicitly rejected. Requests with `maxOutputTokens: 32769` failed in both JSON and SSE checks. A valid and an invalid `continuationToken` both returned answers, so correct continuation is **not verified**. Service-tier choices and `seed` were accepted without proof of their effect. Maps, File Search, Computer Use, agentic video and external file references remain untested. These limited checks do not establish every parameter combination or production availability. Use the native format for the complete contract; OpenAI compatibility is a separate subset and does not provide long decode. ## References * [Official model specification](https://ai.google.dev/gemini-api/docs/models/gemini-4-argon) * [GenerateContent migration guide](https://ai.google.dev/gemini-api/docs/generate-content/latest-model) * [Long decode and continuation](https://ai.google.dev/gemini-api/docs/generate-content/long-decode) * [Structured outputs](https://ai.google.dev/gemini-api/docs/generate-content/structured-output) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/gemini-nano-banana-2-1 Nano Banana 2.1 is Google's `gemini-nano-banana-2.1` image model, the update to Nano Banana 2. Send Google's `generateContent` request body with a `model` field, keep the returned task ID, and check that task for the finished image. Reference images go in `contents` as `fileData` URLs. ## Model IDs | Model ID | Channel | Billing | | --------------------------------- | -------- | ---------------------------------------------------------------- | | `gemini-nano-banana-2.1` | Standard | One flat price per delivered image, at every size | | `gemini-nano-banana-2.1-official` | Official | Per-token rates for input, text/thinking output and image output | Both IDs accept the same request body. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-nano-banana-2.1", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gemini-nano-banana-2.1", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"}, }, }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gemini-nano-banana-2.1', contents: [{ parts: [{ text: 'A ceramic teapot on a linen tablecloth, soft window light' }] }], generationConfig: { responseModalities: ['IMAGE'], imageConfig: { aspectRatio: '16:9', imageSize: '2K' }, }, }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gemini-nano-banana-2.1", "contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The body is Google's `generateContent` request with one addition: `model`, because this endpoint carries no model in its path. The response contains a task ID, not the finished image. Keep API keys in server-side code. Calling `/v1beta/models/...:generateContent` directly is not supported; use this endpoint. ## Parameters | Name | Type | Required | Default | Notes | | ------------------------------------------------- | ---------- | -------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `gemini-nano-banana-2.1`. | | `contents` | Content\[] | Yes | — | 1–32 turns. Each has `parts` and an optional `role` (`user` or `model`); the last turn is `user`. | | `contents[].parts[].text` | string | — | — | A text part. At least one text part is required. | | `contents[].parts[].fileData` | object | No | — | `{"mimeType": "...", "fileUri": "https://..."}`; an image, video, or PDF reference. Up to 14 in total. | | `systemInstruction` | object | No | — | `{"parts": [{"text": "..."}]}`. | | `safetySettings` | object\[] | No | — | `{"category", "threshold"}` pairs; see below. | | `tools` | object\[] | No | — | `[{"googleSearch": {}}]` for web search, or `{"googleSearch": {"searchTypes": {"webSearch": {}, "imageSearch": {}}}}` with either or both types. Grounds the image in live search results; there is no separate search fee. | | `generationConfig.responseModalities` | enum\[] | No | text and image | `["IMAGE"]` for images only, or `["TEXT", "IMAGE"]`. | | `generationConfig.imageConfig.aspectRatio` | enum | No | Input image ratio, else `1:1` | `1:1`, `1:4`, `4:1`, `1:8`, `8:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`. | | `generationConfig.imageConfig.imageSize` | enum | No | `1K` | `1K`, `2K`, `4K`. Uppercase `K`. `512` is not available for this model. | | `generationConfig.candidateCount` | integer | No | `1` | Only `1`. One request returns one image. | | `generationConfig.temperature` | number | No | Model default | 0–2. | | `generationConfig.topP` | number | No | Model default | 0–1. | | `generationConfig.topK` | integer | No | Model default | 1 or more. | | `generationConfig.seed` | integer | No | — | 32-bit integer. | | `generationConfig.maxOutputTokens` | integer | No | Model default | 1–32,768. | | `generationConfig.stopSequences` | string\[] | No | — | Up to 5. | | `generationConfig.mediaResolution` | enum | No | Model default | `MEDIA_RESOLUTION_LOW`, `MEDIA_RESOLUTION_MEDIUM`, `MEDIA_RESOLUTION_HIGH`. Sets how many tokens input media use. | | `generationConfig.thinkingConfig.thinkingLevel` | enum | No | `MEDIUM` | `MINIMAL`, `MEDIUM`, `HIGH`. How much the model reasons before drawing; higher levels take longer. | | `generationConfig.thinkingConfig.includeThoughts` | boolean | No | `false` | Return the model's thought summaries as `output.thoughts`. | Safety categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`, `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`. Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`, `BLOCK_LOW_AND_ABOVE`, `OFF`. Unknown fields are rejected. Not yet available: cached content and `responseFormat`; set the ratio and size with `imageConfig`. `inlineData` is not accepted; pass media as `fileData` URLs. ### Output size | `imageSize` | 1:1 output | Image tokens | | ----------- | ---------- | ------------ | | `1K` | 1024×1024 | 1,120 | | `2K` | 2048×2048 | 1,680 | | `4K` | 4096×4096 | 3,780 | Other aspect ratios keep the same token count; for example `16:9` at `1K` is 1376×768, and `21:9` at `4K` is 6336×2688. ## Modes There is no separate mode parameter or editing endpoint. | Operation | Parameters | | --------------- | ----------------------------------------------------------------------------- | | Text to image | a text part | | Edit or compose | text part + one or more `fileData` parts | | Multi-turn edit | earlier `user` and `model` turns, then a new `user` turn (see the note below) | To continue a conversation, rebuild the `model` turn from the previous task's `output.parts`, in order: a text part becomes `{"text": ..., "thoughtSignature": ...}` and an image part becomes `{"fileData": {"mimeType": "image/", "fileUri": }, "thoughtSignature": ...}`. Keep each `thoughtSignature` exactly as returned: it is the URL of the signature we stored for you (a 4K image's signature is several megabytes), and we restore it before the request reaches the model. Only signatures from your own task results are accepted. ### Edit with a reference image ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-nano-banana-2.1", "contents": [{ "role": "user", "parts": [ {"text": "Turn this photo into a watercolor painting. Keep the composition."}, {"fileData": {"mimeType": "image/jpeg", "fileUri": "https://example.com/photo.jpg"}} ] }] }' ``` Replace the example URL with your own accessible image. ## Media inputs This API accepts URL references only. Base64 `inlineData`, `data:` URLs, and multipart uploads are not accepted. References must be public HTTP(S) URLs, each smaller than 50 MB and 100 MB in total: images (`image/png`, `image/jpeg`, `image/webp`, `image/heic`, `image/heif`), videos (`video/mp4`, `video/mpeg`, `video/mov`, `video/avi`, `video/x-flv`, `video/mpg`, `video/webm`, `video/wmv`, `video/3gpp`), or PDF documents (`application/pdf`). `mimeType` must match the file. URLs are fetched during processing; an inaccessible image fails the task, and a failed task is not charged. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. `gemini-nano-banana-2.1` charges one flat price per delivered image, whatever the size, thinking level, or prompt. `gemini-nano-banana-2.1-official` charges by usage: input tokens (text, reference images and video), text and thinking output tokens, and image output tokens, each at its own rate. The image size is the main factor; see the table above. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns a task reference: ```json { "id": "task_...", "model": "gemini-nano-banana-2.1", "status": "processing", "created_at": 1790310979 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Poll every few seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Complete polling example Run this after the Python submission example above. ```python import time deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task ```json { "id": "task_...", "model": "gemini-nano-banana-2.1", "status": "completed", "created_at": 1790310979, "finished_at": 1790311001, "output": { "created": 1790310999, "data": [{"url": "https://cdn.example.com/media/tasks/task_example/0.jpg"}], "output_format": "jpeg", "usage": { "input_tokens": 22, "output_tokens": 2297, "total_tokens": 2319 } } } ``` | Field | Meaning | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Keep this ID for subsequent queries. | | `status` | `processing`, `completed`, or `failed`. | | `created_at`, `finished_at` | Unix timestamps in seconds. | | `output.data[].url` | The generated image URL. | | `output.text` | Text the model returned alongside the image, when `responseModalities` includes `TEXT`. Thoughts are not included. | | `output.thoughts` | The model's thought summaries, when `includeThoughts` is `true`. Interim images the model draws while thinking are not delivered. | | `output.grounding_metadata` | With Google Search: `webSearchQueries`, `imageSearchQueries`, `searchEntryPoint.renderedContent` (the Search Suggestions HTML you must display) and `groundingChunks` (sources), as Google returns them. | | `output.output_format` | Actual image format. | | `output.parts` | The final response parts in order, for multi-turn editing: `{"text", "thoughtSignature"}` or `{"image": , "thoughtSignature"}`. `thoughtSignature` is a URL; send it back unchanged. | | `output.usage` | Token usage. `output_tokens` counts text, thinking, and image output. | | `error` | Structured error on a failed task. | Streaming (`streamGenerateContent`) is not supported; results are delivered through the task. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. An image withheld by the model's safety filters fails with `content_policy_violation`; a response with no image fails with `no_output`. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your task history before submitting again: the first request may have been accepted. ## Tips * Describe subject, setting, lighting, and style in full sentences. * For an edit, say what should change and what must stay the same. * On `gemini-nano-banana-2.1` the price is the same at every size, so ask for the size you need: `1K` for drafts, `2K` or `4K` for final assets. On `gemini-nano-banana-2.1-official`, larger sizes cost more. * Put the exact words you want rendered in quotes, and keep them short. * Use `MINIMAL` thinking for faster drafts and `HIGH` for dense layouts such as infographics. * Save returned images to your own storage when you need a durable copy. ## Related * [Nano Banana 2.1 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gemini-nano-banana-2-1.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gemini-nano-banana-2-1.md) --- Source: https://toklab.ai/docs/glm-5-3 GLM-5.3 accepts text and returns text or tool calls. It always reasons, supports `low`, `high` and `max` effort, and allows up to 131,072 output tokens. Use **`glm-5.3`** for the Default tier. Its default group is `glm`; `glm-5.3:glm` remains an explicit selection of that same group. Additional groups use their own model suffix. Base URL: `https://api.toklab.ai`. Authenticate with `Authorization: Bearer $TOKLAB_API_KEY`. Keep credentials on your server. Messages also accepts the compatible `x-api-key` header. This reference follows the [Z.ai Chat contract](https://docs.z.ai/api-reference/llm/chat-completion), the manufacturer's [Responses schema](https://docs.bigmodel.cn/openapi/openapi-responses.json), and its [Messages compatibility guide](https://docs.bigmodel.cn/cn/guide/develop/claude/introduction). Model-specific limits come from the [GLM-5.3 guide](https://docs.z.ai/guides/llm/glm-5.3). **Documentation alignment does not establish every live behavior.** Checks on October 29, 2026 completed text and streaming requests in all three formats, Chat function calling, JSON object output, and saved-response continuation. Cache hits, explicit cache lifetimes and every compatibility control were not established. Messages reference fields below are distinguished from manufacturer-documented GLM fields. [OpenAPI specification](https://toklab.ai/docs/glm-5-3.openapi.json) · [Markdown reference](https://toklab.ai/docs/glm-5-3.md) · [Pricing](https://toklab.ai/pricing) ## Quickstart Each example sends one Chat Completions request. `max_tokens: 2048` is an example budget, not the default. Reasoning and the visible answer share that budget; inspect `finish_reason` before treating the answer as complete. ```bash curl https://api.toklab.ai/v1/chat/completions \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H 'Content-Type: application/json' \ -d '{"model":"glm-5.3","messages":[{"role":"user","content":"Explain an idempotency key with one concrete example."}],"reasoning_effort":"low","max_tokens":2048}' ``` ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1") response = client.chat.completions.create( model="glm-5.3", messages=[{"role": "user", "content": "Explain an idempotency key with one concrete example."}], max_tokens=2048, extra_body={"reasoning_effort": "low"}, ) print(response.choices[0].message.content) print(response.usage) ``` ```javascript import OpenAI from 'openai'; const client = new OpenAI({apiKey: process.env.TOKLAB_API_KEY, baseURL: 'https://api.toklab.ai/v1'}); const response = await client.chat.completions.create({ model: 'glm-5.3', messages: [{role: 'user', content: 'Explain an idempotency key with one concrete example.'}], reasoning_effort: 'low', max_tokens: 2048, }); console.log(response.choices[0].message.content); console.log(response.usage); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" "time" ) func main() { body := []byte(`{"model":"glm-5.3","messages":[{"role":"user","content":"Explain an idempotency key with one concrete example."}],"reasoning_effort":"low","max_tokens":2048}`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/chat/completions", bytes.NewReader(body)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 3 * time.Minute} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() data, err := io.ReadAll(res.Body) if err != nil { panic(err) } if res.StatusCode != http.StatusOK { panic(fmt.Sprintf("HTTP %d: %s", res.StatusCode, data)) } fmt.Println(string(data)) } ``` ## Chat Completions `POST /v1/chat/completions` accepts 16 top-level fields. Fields are not nullable unless explicitly stated. Optional fields can be omitted; do not send `null` in place of omission. | Field | Type | Required | Default and constraints | | ------------------ | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | `glm-5.3` (Default) | | `messages` | array | Yes | At least one message; must contain a user or tool message | | `do_sample` | boolean | No | `true`; false makes temperature and top\_p ineffective | | `stream` | boolean | No | `false` | | `thinking` | object | No | `type: enabled`; `clear_thinking: true` | | `reasoning_effort` | string | No | `low`, `high`, `max`; default `max` | | `temperature` | number | No | 0–1 inclusive; default 1 | | `top_p` | number | No | 0.01–1 inclusive; default 0.95 | | `max_tokens` | integer | No | 1–131072; no published Chat default | | `tool_stream` | boolean | No | `false`; true requires `stream: true` | | `tools` | array | No | Function, retrieval or web\_search; up to 128 entries | | `tool_choice` | string | No | `auto` only | | `stop` | string array | No | Up to four strings in the official schema; four were accepted in a live request, but stop matching was not exercised | | `response_format` | object | No | Required `type`: `text` or `json_object`; default text | | `request_id` | string | No | 6–64 characters; unique caller request identifier | | `user_id` | string | No | 6–128 characters; avoid personal information | `system` and `user` messages require string `content`. An `assistant` message can carry string `content`, `reasoning_content` and `tool_calls`. A `tool` message requires `content` and `tool_call_id`. Preserve exact historical reasoning when using `thinking.clear_thinking: false`, including the order of assistant calls and tool results. Thinking cannot be disabled. A function tool uses `{type:"function", function:{name, description, parameters}}`. The name contains 1–64 ASCII letters, digits, underscores or hyphens. The machine schema requires description and parameters; prose mentions omission for parameterless functions. Use the full shape until this conflict is resolved. `parameters` is your function's JSON Schema; it is not interpreted as message content. A retrieval tool uses `{type:"retrieval", retrieval:{knowledge_id, prompt_template?}}`. A knowledge ID belongs to the account serving the request; declaring this tool does not create a knowledge base. A web search tool uses `{type:"web_search", web_search:{search_engine:"search_pro_jina"}}`. Optional fields include `enable`, `search_query`, `count` (1–50), `search_domain_filter`, `search_recency_filter` (`oneDay`, `oneWeek`, `oneMonth`, `oneYear`, `noLimit`), `content_size` (`medium`, `high`), `result_sequence` (`before`, `after`), `search_result`, `require_search` and `search_prompt`. See OpenAPI for exact types. Account-specific search and retrieval availability need live verification. JSON object mode produces JSON, not enforcement of a supplied JSON Schema. Include the desired fields in the prompt and validate the result in your application. ## Responses `POST /v1/responses` accepts 15 top-level create fields. This follows the manufacturer's Responses schema, specialized to GLM-5.3; exact behavior across services remains subject to verification. ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H 'Content-Type: application/json' \ -d '{"model":"glm-5.3","input":[{"type":"message","role":"user","content":"Give a concise example of a safe retry."}],"reasoning":{"effort":"low"},"max_output_tokens":2048,"store":false}' ``` | Field | Type | Required | Default and constraints | | ---------------------- | --------------- | -------- | ------------------------------------------------ | | `model` | string | Yes | `glm-5.3` | | `input` | string or array | Yes | Native input items listed below | | `instructions` | string | No | System instructions | | `stream` | boolean | No | `false` | | `temperature` | number | No | 0–1, at most two decimal places; default 1 | | `top_p` | number | No | 0.01–1, at most two decimal places; default 0.95 | | `max_output_tokens` | integer | No | 1–131072; default 65536, including reasoning | | `stop` | string array | No | No count limit declared in this protocol | | `tools` | array | No | Function, namespace, custom or web\_search | | `tool_choice` | string | No | `none` or `auto` | | `reasoning` | object | No | `effort`: low, high, max; default max | | `text` | object | No | `format.type`: text or json\_object | | `prompt_cache_key` | string | No | Cache routing key; no documented length limit | | `previous_response_id` | string | No | References a previously saved response | | `store` | boolean | No | `false`; whether to save this response | Message input items require `type: "message"`, a role (`user`, `system`, `assistant`, `developer`) and content. Content can be a string, one text block or an array of text blocks. Use `input_text` or assistant `output_text` with a string `text`. Generic image/file schemas do not grant vision capability to this text-only model. Function-call input items require `type: "function_call"`, `name`, `call_id` and a JSON-string `arguments`; `namespace` is optional. Results require `type: "function_call_output"`, `call_id` and string `output`. Reasoning items use `type: "reasoning"` and a **single** `content: {type:"reasoning_text", text:"..."}` object. Preserve it without converting to an array. Function tools require `type: "function"` and `name`, with optional description and parameters. Namespace tools require `type: "namespace"` and `name`, and can contain function `tools`. Custom tools require `type: "custom"` and `name`. Web search tools require `type: "web_search"`. Do not copy Chat's function-required fields into this format. The referenced previous response must have been stored. Saving the current response is a separate choice; `previous_response_id` does not force current `store: true`. The manufacturer's retention period is seven days. A live check successfully saved a response and continued from its ID with current `store: false`; this does not establish every saved-response operation. ### Saved response operations When `store: true` succeeds, keep the returned response ID unchanged. These authenticated operations use the same account that created it: * `GET /v1/responses/{response_id}` retrieves the saved response. * `GET /v1/responses/{response_id}/input_items` lists input items. Optional query fields: `order` (`asc` or `desc`, default `desc`), `limit` (integer 1–100, default 20) and `after` (the prior page's last\_id). * `DELETE /v1/responses/{response_id}` deletes the saved response. A subsequent create request can use the saved ID as `previous_response_id`. Access requires the original user's current model access. Retention is at most seven days; expired or deleted responses cannot be continued. Retrieval, deletion and continuation keep the original account binding. No cancel endpoint is documented. These operations are covered by local contract tests. The October 29 live check confirmed save and continuation; retrieval and input-item listing returned 404, and deletion was not tested. Do not rely on retrieval, listing or deletion until their availability is confirmed. ## Messages compatibility `POST /v1/messages` uses an Anthropic-compatible envelope. Include `anthropic-version: 2023-06-01`. The manufacturer directly demonstrates `model`, `messages`, `max_tokens` and `stream`. It does not publish a complete GLM Messages schema and warns about differences from Claude. The remaining controls are compatibility-reference fields, **not individually verified GLM capabilities**. ```bash curl https://api.toklab.ai/v1/messages \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H 'Content-Type: application/json' \ -H 'anthropic-version: 2023-06-01' \ -d '{"model":"glm-5.3","messages":[{"role":"user","content":"Explain a safe retry in two sentences."}],"max_tokens":2048}' ``` | Field | Shape and validation | Evidence | | ---------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------- | | `model` | Required string `glm-5.3` | GLM example | | `messages` | Required nonempty user/assistant array; string or native text/tool blocks | GLM text example; block shapes use compatibility reference | | `max_tokens` | Required integer 1–131072 | GLM example and model output limit | | `stream` | Boolean; default false | GLM example | | `system` | String or text-block array | Compatibility reference | | `temperature` | Number 0–1 | Compatibility reference; mapping unverified | | `top_p` | Number 0.01–1 | Compatibility reference; mapping unverified | | `top_k` | Nonnegative integer | Compatibility reference; mapping unverified | | `stop_sequences` | String array | Compatibility reference | | `tools` | Client tools: name, input\_schema, optional description | Compatibility reference | | `tool_choice` | Object type auto, none, any or tool; named tool requires name | Compatibility reference | | `thinking` | enabled with budget\_tokens, or adaptive; cannot disable thinking | Compatibility reference plus GLM always-on rule | | `output_config` | Object with effort low, high or max | Compatible field spelling; mapping unverified | | `metadata` | Object with optional user\_id | Compatibility reference | | `cache_control` | Ephemeral marker, optional ttl 5m or 1h | Protocol reference only; GLM explicit TTL behavior unverified | Enabled thinking's compatible budget is at least 1024 and less than max\_tokens. Text blocks require text; thinking history requires thinking and signature; redacted thinking requires data. Tool-use blocks require id, name and input; tool-result blocks require tool\_use\_id. No image, audio or video block is accepted. Explicit cache markers do not establish a cache hit, a lifetime or a separate rate. The model's documented context cache is automatic. ## Output, streaming and usage Chat returns `id`, `created`, `model`, `choices` and `usage`, with optional request\_id and web\_search. Read `choices[].message.content`, `reasoning_content` and `tool_calls`. A tool-call response may have no answer text. SSE sends reasoning, text and tool argument deltas, then `[DONE]`. Join argument fragments by call index. No `stream_options` field is part of the official GLM Chat request. Responses returns the native `output` union: messages, reasoning and tool calls. SSE includes `response.created`, `response.in_progress`, output-item and content-part events, text/reasoning/function-argument deltas, search progress, and terminal `response.completed`, `response.incomplete` or `response.failed`. It does not require a `[DONE]` marker. Preserve indices and sequence numbers. Messages returns a native message envelope with content blocks, stop\_reason and usage. Its event names include message\_start, content\_block\_start/delta/stop, message\_delta and message\_stop. Preserve thinking signatures and tool IDs as opaque history. | Format | Total input | Cached input | Output | | --------- | ------------------------------------------------------------------------------------ | -------------------------------------- | ------------------ | | Chat | prompt\_tokens | prompt\_tokens\_details.cached\_tokens | completion\_tokens | | Responses | input\_tokens | input\_tokens\_details.cached\_tokens | output\_tokens | | Messages | input\_tokens plus cache\_read\_input\_tokens and any cache\_creation\_input\_tokens | cache\_read\_input\_tokens | output\_tokens | Reasoning is a subset of output, not an additional charge. Chat/Responses cached input is a subset of total input. Subtract separately reported cached portions before applying the ordinary input rate. Public responses expose token usage, not monetary charges. [Current prices](https://toklab.ai/pricing) come from live billing settings; failed requests are not charged. ## Validation and errors Invalid types, disabled thinking, unsupported effort, excessive output budgets and media input fail validation. Chat's tool\_stream requires stream. Unsupported top-level fields are omitted rather than forwarded. Credentials are required; insufficient balance prevents a paid request. Errors use the public error envelope (Messages uses its native error shape). Never treat an interrupted stream as a completed answer or automatically resubmit a request with an uncertain result. Blank optional values are omitted; explicit false and zero are preserved. Changing formats starts a new conversation. Its usage estimate needs both reported usage and current rates. --- Source: https://toklab.ai/docs/gpt-6-1-sol GPT-6.1 Sol is OpenAI's upgrade to GPT-6 Sol for complex coding, computer use and professional work, with performance close to GPT-6 Astra at a lower cost. Send the official OpenAI Responses or Chat Completions request to TokLab: change the base URL and the API key, keep the body. ## Model ID | Model ID | Context window | Max output | Reasoning effort | Default effort | | ------------- | ------------------------- | ----------- | --------------------------------------- | -------------- | | `gpt-6.1-sol` | 1.05M tokens (922K input) | 128K tokens | `low`, `medium`, `high`, `xhigh`, `max` | `medium` | Input: text and images. Output: text. Knowledge cutoff: April 30, 2026. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6.1-sol", "input": "Summarize the trade-offs of event sourcing in three bullet points." }' ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1", ) response = client.responses.create( model="gpt-6.1-sol", input="Summarize the trade-offs of event sourcing in three bullet points.", ) print(response.output_text) ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai/v1", }); const response = await client.responses.create({ model: "gpt-6.1-sol", input: "Summarize the trade-offs of event sourcing in three bullet points.", }); console.log(response.output_text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "gpt-6.1-sol", "input": "Summarize the trade-offs of event sourcing in three bullet points."}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/responses", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | The OpenAI endpoints forward your request body as sent and return the official response. Keep the API key in server-side code. ## Parameters Responses API fields: | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `gpt-6.1-sol`. | | `input` | string or object\[] | Yes | — | A prompt, or input items: messages whose `content` holds `input_text` and `input_image` parts. | | `instructions` | string | No | — | System (developer) instructions. | | `max_output_tokens` | integer | No | Model maximum | 16–128000. Includes reasoning tokens. | | `reasoning.effort` | enum | No | `medium` | `low`, `medium`, `high`, `xhigh`, `max`. `none` and `minimal` are not supported. | | `reasoning.summary` | enum | No | — | `auto`, `concise` or `detailed`: return a summary of the reasoning. | | `reasoning.mode` | enum | No | `standard` | `standard` or `pro`. | | `reasoning.context` | enum | No | `auto` | `auto`, `current_turn` or `all_turns`: which earlier reasoning is shown to the model. | | `text.verbosity` | enum | No | `medium` | `low`, `medium` or `high`. | | `text.format` | object | No | — | Structured output, for example `{"type": "json_schema", "name": "...", "schema": {...}}`. | | `temperature`, `top_p`, `top_logprobs` | — | No | — | Not used by GPT-6.1 Sol, which always reasons. Ignored if sent. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `tools`, `tool_choice`, `parallel_tool_calls`, `max_tool_calls`, `include`, `metadata`, `store`, `truncation`, `prompt_cache_key`, `prompt_cache_options`, `prompt_cache_retention`, `context_management`, `moderation`, `prompt`, `previous_response_id`, `conversation`, `user` | — | No | — | Forwarded as sent. | Not available: `background`, `service_tier` (including Batch, Flex and fast mode) and `safety_identifier`. ## Reasoning and effort GPT-6.1 Sol defaults to `medium` and always reasons: `none` and `minimal` are not supported, and `temperature`, `top_p` and `top_logprobs` are not used. Higher effort usually means more output tokens, a longer wait and a higher cost. Reasoning tokens are billed as output tokens and count toward `max_output_tokens`. ## Image input Images go in a user message's `content` as `input_image` parts with an `image_url`: ```json {"role": "user", "content": [ {"type": "input_image", "image_url": "https://example.com/chart.png"}, {"type": "input_text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable image of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including reasoning, * cached input tokens (`usage.input_tokens_details.cached_tokens`), and * cache-write tokens (`usage.input_tokens_details.cache_write_tokens`). When a prompt has more than 272K input tokens, the whole request is billed at the long-context rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official response object: ```json { "id": "resp_...", "object": "response", "status": "completed", "model": "gpt-6.1-sol", "output": [{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "..."}]}], "usage": {"input_tokens": 27, "input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0}, "output_tokens": 102, "output_tokens_details": {"reasoning_tokens": 0}, "total_tokens": 129} } ``` With `"stream": true` the response is a stream of the official events, including `response.created`, `response.output_text.delta` and `response.completed`; the final `response.completed` event carries the usage. ## Chat Completions Existing Chat Completions code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="gpt-6.1-sol", messages=[{"role": "user", "content": "Hello"}], max_completion_tokens=1024, ) print(chat.choices[0].message.content) ``` Set the output limit with `max_completion_tokens` and the effort with `reasoning_effort`. Use the Responses API for tool calling. ## Anthropic Messages format Code written for the Anthropic Messages API can call GPT-6.1 Sol too: send the Messages body to `/v1/messages` with `"model": "gpt-6.1-sol"`. The request is converted to Chat Completions, so a field with no Chat Completions counterpart has no effect. The response carries the official Messages fields and may include a few extra usage fields; read `usage.input_tokens`, `usage.output_tokens` and the official fields. ## Errors Errors use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with the default `medium` effort, use `low` for fast, simple steps and raise the effort only for hard tasks. * Set `max_output_tokens` high enough for the reasoning as well as the answer: it is one budget for both. * Keep long, reused context at the start of the prompt so later requests read it from the cache at the lower rate. ## Related * [GPT-6.1 Sol pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gpt-6-1-sol.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gpt-6-1-sol.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/gpt-6-astra GPT-6 Astra is OpenAI's most capable model, built for the hardest end-to-end work: complex reasoning, coding, research and document creation. Send the official OpenAI Responses or Chat Completions request to TokLab: change the base URL and the API key, keep the body. ## Model ID | Model ID | Context window | Max output | Reasoning effort | Default effort | | ------------- | ------------------------- | ----------- | --------------------------------------- | -------------- | | `gpt-6-astra` | 1.05M tokens (922K input) | 128K tokens | `low`, `medium`, `high`, `xhigh`, `max` | Not documented | Input: text and images. Output: text. Knowledge cutoff: April 30, 2026. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-astra", "input": "Summarize the trade-offs of event sourcing in three bullet points." }' ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1", ) response = client.responses.create( model="gpt-6-astra", input="Summarize the trade-offs of event sourcing in three bullet points.", ) print(response.output_text) ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai/v1", }); const response = await client.responses.create({ model: "gpt-6-astra", input: "Summarize the trade-offs of event sourcing in three bullet points.", }); console.log(response.output_text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "gpt-6-astra", "input": "Summarize the trade-offs of event sourcing in three bullet points."}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/responses", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | The OpenAI endpoints forward your request body as sent and return the official response. Keep the API key in server-side code. ## Parameters Responses API fields: | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -------- | -------------- | ---------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `gpt-6-astra`. | | `input` | string or object\[] | Yes | — | A prompt, or input items: messages whose `content` holds `input_text` and `input_image` parts. | | `instructions` | string | No | — | System (developer) instructions. | | `max_output_tokens` | integer | No | Model maximum | 16–128000. Includes reasoning tokens. | | `reasoning.effort` | enum | No | Not documented | `low`, `medium`, `high`, `xhigh`, `max`. | | `reasoning.summary` | enum | No | — | `auto`, `concise` or `detailed`: return a summary of the reasoning. | | `reasoning.mode` | enum | No | `standard` | `standard` or `pro`. | | `reasoning.context` | enum | No | `auto` | `auto`, `current_turn` or `all_turns`: which earlier reasoning is shown to the model. | | `text.verbosity` | enum | No | `medium` | `low`, `medium` or `high`. | | `text.format` | object | No | — | Structured output, for example `{"type": "json_schema", "name": "...", "schema": {...}}`. | | `temperature` | number | No | — | 0–2. Not accepted: GPT-6 Astra always reasons. Leave it out. | | `top_p` | number | No | — | 0–1. Not accepted: GPT-6 Astra always reasons. Leave it out. | | `top_logprobs` | integer | No | — | 0–20. Not accepted: GPT-6 Astra always reasons. Leave it out. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `tools`, `tool_choice`, `parallel_tool_calls`, `max_tool_calls`, `include`, `metadata`, `store`, `truncation`, `prompt_cache_key`, `prompt_cache_options`, `prompt_cache_retention`, `context_management`, `moderation`, `prompt`, `previous_response_id`, `conversation`, `user` | — | No | — | Forwarded as sent. | Not available: `background`, `service_tier` (including Batch, Flex and fast mode) and `safety_identifier`. ## Reasoning and effort GPT-6 Astra always reasons: `none` is not supported and returns a 400 error. OpenAI does not document a default effort for GPT-6 Astra; leave `reasoning.effort` out to use the model's own default. Higher effort usually means more output tokens, a longer wait and a higher cost. Reasoning tokens are billed as output tokens and count toward `max_output_tokens`. ## Image input Images go in a user message's `content` as `input_image` parts with an `image_url`: ```json {"role": "user", "content": [ {"type": "input_image", "image_url": "https://example.com/chart.png"}, {"type": "input_text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable image of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including reasoning, * cached input tokens (`usage.input_tokens_details.cached_tokens`), and * cache-write tokens (`usage.input_tokens_details.cache_write_tokens`). When a prompt has more than 272K input tokens, the whole request is billed at the long-context rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official response object: ```json { "id": "resp_...", "object": "response", "status": "completed", "model": "gpt-6-astra", "output": [{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "..."}]}], "usage": {"input_tokens": 27, "input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0}, "output_tokens": 102, "output_tokens_details": {"reasoning_tokens": 0}, "total_tokens": 129} } ``` With `"stream": true` the response is a stream of the official events, including `response.created`, `response.output_text.delta` and `response.completed`; the final `response.completed` event carries the usage. ## Chat Completions Existing Chat Completions code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="gpt-6-astra", messages=[{"role": "user", "content": "Hello"}], max_completion_tokens=1024, ) print(chat.choices[0].message.content) ``` Set the output limit with `max_completion_tokens` and the effort with `reasoning_effort`. Chat Completions does not support function calling with GPT-6 Astra; use the Responses API for tools. ## Anthropic Messages format Code written for the Anthropic Messages API can call GPT-6 Astra too: send the Messages body to `/v1/messages` with `"model": "gpt-6-astra"`. The request is converted to Chat Completions, so a field with no Chat Completions counterpart has no effect. The response carries the official Messages fields and may include a few extra usage fields; read `usage.input_tokens`, `usage.output_tokens` and the official fields. ## Errors Errors use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with `medium` and raise the effort only for tasks that need deeper reasoning; effort changes both quality and cost. * Set `max_output_tokens` high enough for the reasoning as well as the answer: it is one budget for both. * Keep long, reused context at the start of the prompt so later requests read it from the cache at the lower rate. ## Related * [GPT-6 Astra pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gpt-6-astra.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gpt-6-astra.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/gpt-6-luna GPT-6 Luna is OpenAI's most efficient GPT-6 model, built for focused, high-volume tasks, and the lowest-cost model in the GPT-6 family. Send the official OpenAI Responses or Chat Completions request to TokLab: change the base URL and the API key, keep the body. ## Model ID | Model ID | Context window | Max output | Reasoning effort | Default effort | | ------------ | ------------------------- | ----------- | ----------------------------------------------- | -------------- | | `gpt-6-luna` | 1.05M tokens (922K input) | 128K tokens | `none`, `low`, `medium`, `high`, `xhigh`, `max` | `medium` | Input: text and images. Output: text. Knowledge cutoff: May 18, 2026. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-luna", "input": "Summarize the trade-offs of event sourcing in three bullet points." }' ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1", ) response = client.responses.create( model="gpt-6-luna", input="Summarize the trade-offs of event sourcing in three bullet points.", ) print(response.output_text) ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai/v1", }); const response = await client.responses.create({ model: "gpt-6-luna", input: "Summarize the trade-offs of event sourcing in three bullet points.", }); console.log(response.output_text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "gpt-6-luna", "input": "Summarize the trade-offs of event sourcing in three bullet points."}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/responses", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | The OpenAI endpoints forward your request body as sent and return the official response. Keep the API key in server-side code. ## Parameters Responses API fields: | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `gpt-6-luna`. | | `input` | string or object\[] | Yes | — | A prompt, or input items: messages whose `content` holds `input_text` and `input_image` parts. | | `instructions` | string | No | — | System (developer) instructions. | | `max_output_tokens` | integer | No | Model maximum | 16–128000. Includes reasoning tokens. | | `reasoning.effort` | enum | No | `medium` | `none`, `low`, `medium`, `high`, `xhigh`, `max`. | | `reasoning.summary` | enum | No | — | `auto`, `concise` or `detailed`: return a summary of the reasoning. | | `reasoning.mode` | enum | No | `standard` | `standard` or `pro`. | | `reasoning.context` | enum | No | `auto` | `auto`, `current_turn` or `all_turns`: which earlier reasoning is shown to the model. | | `text.verbosity` | enum | No | `medium` | `low`, `medium` or `high`. | | `text.format` | object | No | — | Structured output, for example `{"type": "json_schema", "name": "...", "schema": {...}}`. | | `temperature` | number | No | — | 0–2. Accepted only with `reasoning.effort` set to `none`. | | `top_p` | number | No | — | 0–1. Accepted only with `reasoning.effort` set to `none`. | | `top_logprobs` | integer | No | — | 0–20. Accepted only with `reasoning.effort` set to `none`. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `tools`, `tool_choice`, `parallel_tool_calls`, `max_tool_calls`, `include`, `metadata`, `store`, `truncation`, `prompt_cache_key`, `prompt_cache_options`, `prompt_cache_retention`, `context_management`, `moderation`, `prompt`, `previous_response_id`, `conversation`, `user` | — | No | — | Forwarded as sent. | Not available: `background`, `service_tier` (including Batch, Flex and fast mode) and `safety_identifier`. ## Reasoning and effort GPT-6 Luna defaults to `medium`. At `none` the model answers without reasoning, and only then are `temperature`, `top_p` and `top_logprobs` accepted. Higher effort usually means more output tokens, a longer wait and a higher cost. Reasoning tokens are billed as output tokens and count toward `max_output_tokens`. ## Image input Images go in a user message's `content` as `input_image` parts with an `image_url`: ```json {"role": "user", "content": [ {"type": "input_image", "image_url": "https://example.com/chart.png"}, {"type": "input_text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable image of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including reasoning, * cached input tokens (`usage.input_tokens_details.cached_tokens`), and * cache-write tokens (`usage.input_tokens_details.cache_write_tokens`). When a prompt has more than 272K input tokens, the whole request is billed at the long-context rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official response object: ```json { "id": "resp_...", "object": "response", "status": "completed", "model": "gpt-6-luna", "output": [{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "..."}]}], "usage": {"input_tokens": 27, "input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0}, "output_tokens": 102, "output_tokens_details": {"reasoning_tokens": 0}, "total_tokens": 129} } ``` With `"stream": true` the response is a stream of the official events, including `response.created`, `response.output_text.delta` and `response.completed`; the final `response.completed` event carries the usage. ## Chat Completions Existing Chat Completions code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="gpt-6-luna", messages=[{"role": "user", "content": "Hello"}], max_completion_tokens=1024, ) print(chat.choices[0].message.content) ``` Set the output limit with `max_completion_tokens` and the effort with `reasoning_effort`. On Chat Completions, GPT-6 Luna supports function calling only with `reasoning_effort` set to `none`; use the Responses API for reasoning with tools. ## Anthropic Messages format Code written for the Anthropic Messages API can call GPT-6 Luna too: send the Messages body to `/v1/messages` with `"model": "gpt-6-luna"`. The request is converted to Chat Completions, so a field with no Chat Completions counterpart has no effect. The response carries the official Messages fields and may include a few extra usage fields; read `usage.input_tokens`, `usage.output_tokens` and the official fields. ## Errors Errors use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * For classification and extraction, try `none` first: it is the fastest and cheapest setting. * Set `max_output_tokens` high enough for the reasoning as well as the answer: it is one budget for both. * Keep long, reused context at the start of the prompt so later requests read it from the cache at the lower rate. ## Related * [GPT-6 Luna pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gpt-6-luna.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gpt-6-luna.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/gpt-6-sol GPT-6 Sol is OpenAI's GPT-6 model for complex coding and agentic workflows, between GPT-6 Astra and GPT-6 Luna in capability and price. Send the official OpenAI Responses or Chat Completions request to TokLab: change the base URL and the API key, keep the body. ## Model ID | Model ID | Context window | Max output | Reasoning effort | Default effort | | ----------- | ------------------------- | ----------- | ----------------------------------------------- | -------------- | | `gpt-6-sol` | 1.05M tokens (922K input) | 128K tokens | `none`, `low`, `medium`, `high`, `xhigh`, `max` | `medium` | Input: text and images. Output: text. Knowledge cutoff: April 20, 2026. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-sol", "input": "Summarize the trade-offs of event sourcing in three bullet points." }' ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1", ) response = client.responses.create( model="gpt-6-sol", input="Summarize the trade-offs of event sourcing in three bullet points.", ) print(response.output_text) ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai/v1", }); const response = await client.responses.create({ model: "gpt-6-sol", input: "Summarize the trade-offs of event sourcing in three bullet points.", }); console.log(response.output_text); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "gpt-6-sol", "input": "Summarize the trade-offs of event sourcing in three bullet points."}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/responses", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- | | OpenAI Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | | OpenAI Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | The OpenAI endpoints forward your request body as sent and return the official response. Keep the API key in server-side code. ## Parameters Responses API fields: | Name | Type | Required | Default | Notes | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `gpt-6-sol`. | | `input` | string or object\[] | Yes | — | A prompt, or input items: messages whose `content` holds `input_text` and `input_image` parts. | | `instructions` | string | No | — | System (developer) instructions. | | `max_output_tokens` | integer | No | Model maximum | 16–128000. Includes reasoning tokens. | | `reasoning.effort` | enum | No | `medium` | `none`, `low`, `medium`, `high`, `xhigh`, `max`. | | `reasoning.summary` | enum | No | — | `auto`, `concise` or `detailed`: return a summary of the reasoning. | | `reasoning.mode` | enum | No | `standard` | `standard` or `pro`. | | `reasoning.context` | enum | No | `auto` | `auto`, `current_turn` or `all_turns`: which earlier reasoning is shown to the model. | | `text.verbosity` | enum | No | `medium` | `low`, `medium` or `high`. | | `text.format` | object | No | — | Structured output, for example `{"type": "json_schema", "name": "...", "schema": {...}}`. | | `temperature` | number | No | — | 0–2. Accepted only with `reasoning.effort` set to `none`. | | `top_p` | number | No | — | 0–1. Accepted only with `reasoning.effort` set to `none`. | | `top_logprobs` | integer | No | — | 0–20. Accepted only with `reasoning.effort` set to `none`. | | `stream` | boolean | No | `false` | Stream the response as server-sent events. | | `tools`, `tool_choice`, `parallel_tool_calls`, `max_tool_calls`, `include`, `metadata`, `store`, `truncation`, `prompt_cache_key`, `prompt_cache_options`, `prompt_cache_retention`, `context_management`, `moderation`, `prompt`, `previous_response_id`, `conversation`, `user` | — | No | — | Forwarded as sent. | Not available: `background`, `service_tier` (including Batch, Flex and fast mode) and `safety_identifier`. ## Reasoning and effort GPT-6 Sol defaults to `medium`. At `none` the model answers without reasoning, and only then are `temperature`, `top_p` and `top_logprobs` accepted. Higher effort usually means more output tokens, a longer wait and a higher cost. Reasoning tokens are billed as output tokens and count toward `max_output_tokens`. ## Image input Images go in a user message's `content` as `input_image` parts with an `image_url`: ```json {"role": "user", "content": [ {"type": "input_image", "image_url": "https://example.com/chart.png"}, {"type": "input_text", "text": "What does this chart show?"} ]} ``` Replace the example URL with a publicly reachable image of your own. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * output tokens, including reasoning, * cached input tokens (`usage.input_tokens_details.cached_tokens`), and * cache-write tokens (`usage.input_tokens_details.cache_write_tokens`). When a prompt has more than 272K input tokens, the whole request is billed at the long-context rates. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming request returns the official response object: ```json { "id": "resp_...", "object": "response", "status": "completed", "model": "gpt-6-sol", "output": [{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "..."}]}], "usage": {"input_tokens": 27, "input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0}, "output_tokens": 102, "output_tokens_details": {"reasoning_tokens": 0}, "total_tokens": 129} } ``` With `"stream": true` the response is a stream of the official events, including `response.created`, `response.output_text.delta` and `response.completed`; the final `response.completed` event carries the usage. ## Chat Completions Existing Chat Completions code only needs a new base URL and model ID: ```python from openai import OpenAI client = OpenAI(api_key="YOUR_TOKLAB_KEY", base_url="https://api.toklab.ai/v1") chat = client.chat.completions.create( model="gpt-6-sol", messages=[{"role": "user", "content": "Hello"}], max_completion_tokens=1024, ) print(chat.choices[0].message.content) ``` Set the output limit with `max_completion_tokens` and the effort with `reasoning_effort`. On Chat Completions, GPT-6 Sol supports function calling only with `reasoning_effort` set to `none`; use the Responses API for reasoning with tools. ## Anthropic Messages format Code written for the Anthropic Messages API can call GPT-6 Sol too: send the Messages body to `/v1/messages` with `"model": "gpt-6-sol"`. The request is converted to Chat Completions, so a field with no Chat Completions counterpart has no effect. The response carries the official Messages fields and may include a few extra usage fields; read `usage.input_tokens`, `usage.output_tokens` and the official fields. ## Errors Errors use `{"error": {"code": ..., "message": "..."}}`. The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with the default `medium` effort, use `none` for fast, simple steps and raise the effort only for hard tasks. * Set `max_output_tokens` high enough for the reasoning as well as the answer: it is one budget for both. * Keep long, reused context at the start of the prompt so later requests read it from the cache at the lower rate. ## Related * [GPT-6 Sol pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gpt-6-sol.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gpt-6-sol.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/gpt-image-2 GPT Image 2 accepts a text prompt and optional reference images. Submit once, keep the returned task ID, and check that task for the finished images. It is sold on two channels, each with its own model ID; both read the same parameters. ## Model IDs | Model ID | Channel | Billing | | ---------------------- | -------- | ------------------------------------------------------------ | | `gpt-image-2` | Standard | One flat price per delivered image, at any size or quality | | `gpt-image-2-official` | Official | The tokens each render reports (text input and image output) | Both IDs accept the same parameters and support every mode; only billing differs. See the [pricing page](https://toklab.ai/pricing) for current prices. The examples below use `gpt-image-2`; replace it with `gpt-image-2-official` to bill by tokens. ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "An amber glass bottle on a cream background, studio lighting", "size": "1024x1024", "quality": "low" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gpt-image-2", "prompt": "An amber glass bottle on a cream background, studio lighting", "size": "1024x1024", "quality": "low", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-image-2', prompt: 'An amber glass bottle on a cream background, studio lighting', size: '1024x1024', quality: 'low', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gpt-image-2", "prompt": "An amber glass bottle on a cream background, studio lighting", "size": "1024x1024", "quality": "low" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The same endpoint handles generation, reference edits, and masked edits. The response contains a task ID, not the finished image. Keep API keys in server-side code. ## Parameters | Name | Type | Required | Default | Notes | | -------------------- | --------- | -------- | -------------- | ------------------------------------------------------------------------------------ | | `model` | string | Yes | — | `gpt-image-2` or `gpt-image-2-official` | | `prompt` | string | Yes | — | Nonblank; up to 32,000 characters. | | `images` | object\[] | No | — | 1–16 objects shaped as `{"image_url":"https://..."}`; adding images selects editing. | | `mask` | object | No | — | `{"image_url":"https://..."}`; requires `images`. | | `size` | string | No | `auto` | `auto` or `WIDTHxHEIGHT`, subject to the rules below. | | `quality` | enum | No | `auto` | `auto`, `low`, `medium`, `high`. | | `background` | enum | No | `auto` | `auto`, `opaque`, `transparent`. | | `output_format` | enum | No | `png` | `png`, `jpeg`. | | `output_compression` | integer | No | `100` for JPEG | 0–100; send only with `jpeg`. Zero is valid. | | `n` | integer | No | `1` | 1–10 images. | | `moderation` | enum | No | `auto` | `auto`, `low`. | | `user` | string | No | — | Optional application end-user identifier. Avoid personal information. | ### Size rules Common choices are `1024x1024`, `1536x1024`, and `1024x1536`. Custom dimensions must satisfy every rule: * Width and height are multiples of 16. * Neither edge exceeds 3840 pixels. * The aspect ratio is between 1:3 and 3:1. * Total area is between 655,360 and 8,294,400 pixels, inclusive. `auto` leaves the output dimensions to the model. Do not send aspect ratios such as `16:9` as `size`. Send the final dimensions as `size`; there are no separate `resolution` or `aspect_ratio` parameters. For example, a 16:9 image at 4K is `size: "3840x2160"`, 9:16 at 4K is `"2160x3840"`, and 1:1 at 2K is `"2048x2048"`. OpenAI describes resolutions above 2560×1440 as experimental. They are accepted within the limits above; higher resolution is not a guarantee of better detail. ### Quality tiers Use `low` for drafts and compare results before choosing a higher tier. `auto` lets the model choose; it does not guarantee a particular tier or cost. ### Transparent backgrounds Transparency is in preview for GPT Image 2. For a transparent background, set `background: "transparent"` and use PNG. JPEG does not support transparency. Compression applies only to JPEG. Optional scalar settings (`n`, `size`, `quality`, `background`, `output_format`, `output_compression`, `moderation`) accept `null` as omission. Unknown fields are rejected. `input_fidelity` is not configurable for GPT Image 2; reference inputs always use high fidelity. `style` and `response_format` belong to other image models and are not accepted here. ## Modes There is no separate mode parameter or editing endpoint to choose. | Operation | Parameters | | -------------- | ---------------------------- | | Text to image | `prompt` | | Reference edit | `prompt` + `images` | | Masked edit | `prompt` + `images` + `mask` | ### Edit reference images ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "Make the bottle blue. Preserve the composition and lighting.", "images": [{"image_url": "https://example.com/reference.png"}], "mask": {"image_url": "https://example.com/mask.png"}, "output_format": "jpeg", "output_compression": 90 }' ``` Replace both example URLs with your own accessible images. Omit `mask` for a reference edit without a selected region. ## Media inputs This API accepts URL references only. OpenAI Files IDs, base64 data URLs, and multipart uploads are not accepted. Reference images must be public HTTP(S) URLs pointing to PNG, JPEG, or WebP files smaller than 50 MB each. A mask must be a PNG smaller than 4 MB, with the same dimensions as the first reference image; its transparent area marks what to edit. A mask guides the model and does not guarantee pixel-perfect boundaries. For multiple references, the mask applies to the first image. URL media is validated during processing; invalid or inaccessible media can produce a failed task. API requests use JSON URL objects: do not send file bytes, base64, `data:` URLs, `blob:` URLs, or multipart form data. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. `gpt-image-2` (Standard) charges one flat price per delivered image, whatever the quality, size, or prompt. On `gpt-image-2-official` (Official), the final cost depends on input and output usage: quality, output dimensions, reference images, prompt length, and image count can all affect it. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns a task reference: ```json { "id": "task_...", "model": "gpt-image-2", "status": "processing", "created_at": 1789970508 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Poll at a modest interval, such as every three seconds, until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Complete polling example Run this after the Python submission example above. It uses the returned `task_id` and waits up to ten minutes. Reaching this local deadline stops polling only; retain the ID and resume querying the same task. ```python import time print(f"Task ID: {task_id}") deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task A completed task returns hosted image URLs and usage: ```json { "id": "task_...", "model": "gpt-image-2", "status": "completed", "created_at": 1789970508, "finished_at": 1789970538, "output": { "created": 1789970532, "data": [{"url": "https://cdn.example.com/media/tasks/task_example/0.png"}], "usage": { "input_tokens": 29, "output_tokens": 196, "total_tokens": 225 } } } ``` | Field | Meaning | | --------------------------- | --------------------------------------------------------------------------------------------- | | `id` | Keep this ID for subsequent queries. | | `status` | `processing`, `completed`, or `failed`. | | `created_at`, `finished_at` | Unix timestamps in seconds; completion time is unset or zero while processing. | | `output.data[].url` | Generated image URLs, available on completion. | | `output.size` | Actual output dimensions, when reported. | | `output.quality` | Actual quality tier, when reported. | | `output.background` | Actual background, when reported. | | `output.output_format` | Actual image format, when reported. | | `output.usage` | Reported token usage, when available. Detail objects may contain text and image token counts. | | `error` | Structured error on a failed task. | This API uses asynchronous task delivery. It is not a synchronous Images SDK replacement; `stream` and `partial_images` are not supported. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. All model APIs use the same error envelope. ```json { "id": "task_...", "status": "failed", "error": { "code": 60002, "message": "Generation could not be completed. Please try again." } } ``` If submission itself times out, check your task history before submitting again: the first request may have been accepted. ## Tips * Describe materials, composition, and lighting in the prompt. * For an edit, specify both the change and what should remain unchanged. * Use a mask when only a selected area should change. * Save returned images to your own storage when you need a durable copy. ## Related * [GPT Image 2 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/gpt-image-2.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/gpt-image-2.md) --- Source: https://toklab.ai/docs/gpt-image-2-5 GPT Image 2.5 comes as two models, Flare and Sunburst, and both take exactly the same request body. A request returns a task ID straight away; the images arrive on that task when rendering finishes. Text-to-image, reference edits and masked edits all go to the same endpoint. ## Model IDs | Model ID | Model | Billing | | --------------------------------- | --------------------------------------------------- | ------------------------------------- | | `gpt-image-2.5-flare` | Flare, the faster of the two | Fixed price per image, set by quality | | `gpt-image-2.5-sunburst` | Sunburst, slower, holds detail better through edits | Fixed price per image, set by quality | | `gpt-image-2.5-flare-official` | Flare | Input and output tokens | | `gpt-image-2.5-sunburst-official` | Sunburst | Input and output tokens | Switching between the four IDs never requires a change to the request body. Current rates for each one are on the [GPT Image 2.5 page](https://toklab.ai/models/gpt-image-2-5#pricing). ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2.5-flare", "prompt": "A stack of three linen-bound notebooks on a walnut desk, morning side light", "size": "1024x1024", "quality": "low" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "gpt-image-2.5-flare", "prompt": "A stack of three linen-bound notebooks on a walnut desk, morning side light", "size": "1024x1024", "quality": "low", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-image-2.5-flare', prompt: 'A stack of three linen-bound notebooks on a walnut desk, morning side light', size: '1024x1024', quality: 'low', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "gpt-image-2.5-flare", "prompt": "A stack of three linen-bound notebooks on a walnut desk, morning side light", "size": "1024x1024", "quality": "low" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | What the request contains decides the operation: a prompt alone generates, a prompt with `images` edits, and adding `mask` limits the edit to a region. The response is a task, never image bytes. Call the endpoint from your server so the key stays out of the browser. ## Parameters | Name | Type | Required | Default | Notes | | -------------------- | --------- | -------- | -------------- | -------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | One of the four IDs above. | | `prompt` | string | Yes | — | Must contain non-whitespace text; at most 32,000 characters. | | `images` | object\[] | No | — | 1 to 16 entries, each `{"image_url":"https://..."}`. Sending this makes the request an edit. | | `mask` | object | No | — | `{"image_url":"https://..."}`. Only valid together with `images`. | | `size` | string | No | `auto` | `auto` or `WIDTHxHEIGHT` within the size rules below. | | `quality` | enum | No | `auto` | `auto`, `low`, `medium`, `high`, `xhigh`, `max`. | | `background` | enum | No | `auto` | `auto`, `opaque`, `transparent`. | | `output_format` | enum | No | `png` | `png` or `jpeg`. | | `output_compression` | integer | No | `100` for JPEG | 0 to 100, JPEG only. 0 is a valid value. | | `n` | integer | No | `1` | 1 to 10 images per request. | | `moderation` | enum | No | `auto` | `auto` or `low`. | | `user` | string | No | — | Your own identifier for the end user. Keep personal data out of it. | ### Size rules `1024x1024`, `1536x1024` and `1024x1536` are the usual picks. A custom size passes only if all four of these hold: * Width and height are both multiples of 16. * Neither side is longer than 3840 pixels. * Width divided by height is between 1:3 and 3:1. * Width times height is between 655,360 and 8,294,400 pixels, both ends included. So `3840x2160` and `2880x2880` pass, while `4096x2304` fails on the edge limit. With `auto` the model picks the dimensions. Ratio strings such as `16:9` are not accepted as `size`. In the Playground, Ratio mode turns an aspect ratio plus a 1K, 2K or 4K preset into a single `size` value and shows it before you submit. There is no `resolution` or `aspect_ratio` field in the API; send the computed `size`. OpenAI labels output above 2560×1440 experimental: those sizes are accepted, but a bigger canvas does not promise more detail. ### Quality GPT Image 2 tops out at `high`; GPT Image 2.5 adds `xhigh` and `max`. Each step up renders more slowly. On the token-billed IDs it also produces more output tokens: at 1024x1024 we recorded 196 for `low`, 439 for `medium`, 1,756 for `high`, 3,122 for `xhigh` and 7,024 for `max`. Treat those as single observations. Size and image content move the count. `auto` hands the choice to the model, so neither the tier nor the cost is fixed in advance. Iterating at `low` and moving up only for the keeper is the cheapest way to work. ### Transparent backgrounds Set `background: "transparent"` with PNG output. A transparent request with `output_format: "jpeg"` is rejected, because JPEG has no alpha channel. `output_compression` is likewise rejected unless the format is JPEG. ### Other request rules * The scalar options (`n`, `size`, `quality`, `background`, `output_format`, `output_compression`, `moderation`) treat `null` as not sent. * Any field not listed above is rejected, including `style`, `response_format` and `input_fidelity`. * The Playground does not send `user`; it exists for API callers. ## Modes | Operation | Send | | -------------- | ---------------------------- | | Text to image | `prompt` | | Reference edit | `prompt` + `images` | | Masked edit | `prompt` + `images` + `mask` | ### Edit example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2.5-sunburst", "prompt": "Recolour the mug to deep forest green. Keep the table, the light and the steam exactly as they are.", "images": [{"image_url": "https://example.com/mug.png"}], "mask": {"image_url": "https://example.com/mug-mask.png"}, "output_format": "jpeg", "output_compression": 90 }' ``` Point both URLs at images you host. Drop `mask` to let the model edit the whole picture. ## Media inputs Inputs are URLs only. Base64, `data:` and `blob:` URLs, multipart uploads, raw bytes and OpenAI Files IDs are all refused. The Playground uploads the files you pick and sends their URLs for you. * Reference images: public HTTP(S) URLs to PNG, JPEG or WebP, each under 50 MB. * Mask: a PNG under 4 MB with the same pixel dimensions as the first reference image. Transparent pixels mark the area to change. With several references, the mask applies to the first. The model treats the mask as guidance, so edges are not guaranteed to be pixel-exact. Media is fetched while the task runs; a URL that cannot be read fails the task, and a failed task is not charged. ## Billing The Standard IDs charge a fixed amount for each delivered image, and the amount depends on the model and the quality you pick. The `-official` IDs charge for the input and output tokens the render actually uses, so quality, size, reference images, prompt length and `n` all change the total. Rates are listed on the [model page](https://toklab.ai/models/gpt-image-2-5#pricing) and read from the same ledger that bills your account. The Playground estimate combines a measured sample with the current rate. It is a guide, not a quote; the actual charge for each task is in your usage history. ## Response Submitting returns the task: ```json { "id": "task_...", "model": "gpt-image-2.5-flare", "status": "processing", "created_at": 1789970508 } ``` ### Poll the task ```bash curl https://api.toklab.ai/v1/tasks/YOUR_TASK_ID \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Check every few seconds until `status` becomes `completed` or `failed`. If a poll times out, the render has not failed; ask about the same task ID again. Submitting a second request to find out where the first one is just creates a second paid task. ### Polling example This continues the Python example above. It stops waiting after ten minutes, which ends only the local loop: the task keeps running and the same ID can be queried later. ```python import time print(f"Task ID: {task_id}") deadline = time.monotonic() + 600 while time.monotonic() < deadline: result = requests.get( f"https://api.toklab.ai/v1/tasks/{task_id}", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, timeout=30, ) result.raise_for_status() task = result.json() if task["status"] == "completed": for image in task["output"]["data"]: print(image["url"]) break if task["status"] == "failed": raise RuntimeError(task["error"]["message"]) time.sleep(3) else: raise TimeoutError(f"Still waiting. Resume polling task {task_id}.") ``` ### Completed task ```json { "id": "task_...", "model": "gpt-image-2.5-flare", "status": "completed", "created_at": 1789970508, "finished_at": 1789970538, "output": { "created": 1789970532, "data": [{"url": "https://.../task_example/0.png"}], "usage": { "input_tokens": 29, "output_tokens": 196, "total_tokens": 225 } } } ``` | Field | Meaning | | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `id` | The task ID to query. | | `status` | `processing`, `completed` or `failed`. | | `created_at`, `finished_at` | Unix seconds. `finished_at` is empty or zero until the task ends. | | `output.data[].url` | Hosted image URLs, present once the task completes. Copy them to your own storage if you need them long term. | | `output.size`, `output.quality`, `output.background`, `output.output_format` | What was actually rendered, when the model reports it. | | `output.usage` | Token usage, when reported. May include a text and image breakdown. | | `error` | Present on failed tasks. | Delivery is asynchronous, so this is not a drop-in for the synchronous OpenAI Images SDK, and `stream` and `partial_images` are not available. ## Errors A request refused before a task exists gets an HTTP error status and an `error` object. A task that fails later still answers the poll with HTTP 200, `status: "failed"` and an `error` object: ```json { "id": "task_...", "status": "failed", "error": { "code": 60002, "message": "Generation could not be completed. Please try again." } } ``` Every model shares one error format; codes, statuses and when to retry are in the [error catalog](https://toklab.ai/docs/api/errors). If the submit call itself times out, look in your task history before retrying, since the first request may already have been accepted. ## Related * [GPT Image 2.5 Playground and pricing](https://toklab.ai/models/gpt-image-2-5) * [Task lifecycle](https://toklab.ai/docs/api/tasks) * [OpenAPI schema](https://toklab.ai/docs/gpt-image-2-5.openapi.json) * [This page as Markdown](https://toklab.ai/docs/gpt-image-2-5.md) --- Source: https://toklab.ai/docs/grok-4-7 Use `grok-4.7` with one of the three formats below. Authentication uses your TokLab API key. Current token prices are on the [pricing page](https://toklab.ai/pricing). ## Quick start ```bash curl https://api.toklab.ai/v1/responses \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"grok-4.7","input":"What is 2 + 2?","reasoning":{"effort":"low"},"max_output_tokens":64,"store":false}' ``` The JSON response includes `output` items and `usage`. Retain all output items when building conversation history, including reasoning and tool items. ## Request formats | Format | Endpoint | Required fields | | ---------------- | --------------------------- | --------------------------------- | | Responses | `POST /v1/responses` | `model`, `input` | | Chat Completions | `POST /v1/chat/completions` | `model`, `messages` | | Messages | `POST /v1/messages` | `model`, `messages`, `max_tokens` | Use `Content-Type: application/json` and `Authorization: Bearer $TOKLAB_API_KEY`. Messages clients can also send `anthropic-version: 2023-06-01`. ## Parameters and constraints The [OpenAPI specification](https://toklab.ai/docs/grok-4-7.openapi.json) contains the full nested request and response schemas. The tables below list every supported top-level request field. Unknown fields and parameters officially ignored by this model are discarded. A supported parameter with an invalid value remains invalid. Optional nullable fields accept explicit `null`; leaving a field out uses its API default. API clients can still send `user`. * Context: 500,000 tokens, including the conversation and output. * Reasoning effort: `low`, `medium`, `high`, `xhigh`; default `high`. * `max_completion_tokens` and `max_output_tokens` default to 128,000 **visible** output tokens. Reasoning and function-call tokens are outside that visible-output limit. This is a default, not a maximum output capability claim. * Output limits must be positive integers. The API also enforces its existing integer safety ceiling of 1,073,741,823; context capacity still applies. * `temperature`: 0 through 2, default 1. `top_p`: greater than 0 and at most 1, default 1. Responses `min_p`: 0 through 1; `top_k`: integer at least 1. * Up to 350 tool definitions. `stream_options` requires `stream: true`. * `instructions` and `previous_response_id` cannot be combined. Reasoning summaries are always detailed. {/* grok-parameters:start */} ### Responses parameters | Field | Type | Rule | | ---------------------- | --------------------- | ------------------------------------------------------------------------------- | | `include` | array or null | Array of additional response fields to include. | | `input` (required) | object or alternative | Text string or complete input-item array. | | `instructions` | string or null | System instructions; cannot be combined with `previous_response_id`. | | `max_output_tokens` | integer or null | Visible-output limit; default 128,000. | | `max_turns` | integer or null | Integer maximum number of agent turns. | | `min_p` | number or null | Number from 0 to 1. | | `model` (required) | string | Fixed to `grok-4.7`. | | `parallel_tool_calls` | boolean or null | Boolean; default true. | | `previous_response_id` | string or null | String response ID; continuation by ID is currently unavailable. | | `prompt_cache_key` | string or null | String cache key. | | `reasoning` | object | Reasoning configuration; effort defaults to `high`. | | `reasoning_effort` | string or null | `low`, `medium`, `high`, `xhigh`; default `high`. | | `safety_identifier` | string or null | Optional caller-supplied safety identifier. | | `search_parameters` | object | Search configuration. | | `service_tier` | string | `auto`, `default`, `priority`, `fast`; priority and fast double token rates. | | `store` | boolean or null | Boolean; default true. Stored-response operations are currently unavailable. | | `stream` | boolean or null | Boolean; default false. | | `temperature` | number or null | Number from 0 to 2; default 1. | | `text` | object | Text response configuration, including `format`. | | `tool_choice` | object or alternative | Automatic, disabled, required or a selected tool; syntax depends on the format. | | `tools` | array or null | Tool definitions; at most 350. | | `top_k` | integer or null | Integer; Responses requires at least 1. | | `top_p` | number or null | Number greater than 0 and at most 1; default 1. | | `user` | string or null | Optional caller-supplied identifier; hidden in the playground. | ### Chat Completions parameters | Field | Type | Rule | | ----------------------- | --------------------- | ------------------------------------------------------------------------------- | | `deferred` | boolean or null | Boolean; default false. Deferred completion is currently unavailable. | | `max_completion_tokens` | integer or null | Visible-output limit; default 128,000. | | `max_tokens` | integer or null | Positive visible-output limit. Required for Messages. | | `messages` (required) | array | Conversation messages in this format. | | `model` (required) | string | Fixed to `grok-4.7`. | | `n` | integer or null | Integer at least 1; default 1. | | `parallel_tool_calls` | boolean or null | Boolean; default true. | | `prompt_cache_key` | string or null | String cache key. | | `reasoning_effort` | string or null | `low`, `medium`, `high`, `xhigh`; default `high`. | | `response_format` | object or alternative | Text, JSON object or JSON schema output. | | `safety_identifier` | string or null | Optional caller-supplied safety identifier. | | `search_parameters` | object | Search configuration. | | `seed` | integer or null | Integer sampling seed. | | `service_tier` | string | `auto`, `default`, `priority`, `fast`; priority and fast double token rates. | | `stream` | boolean or null | Boolean; default false. | | `stream_options` | object | Options for streaming; requires `stream: true`. | | `temperature` | number or null | Number from 0 to 2; default 1. | | `tool_choice` | object or alternative | Automatic, disabled, required or a selected tool; syntax depends on the format. | | `tools` | array or null | Tool definitions; at most 350. | | `top_p` | number or null | Number greater than 0 and at most 1; default 1. | | `user` | string or null | Optional caller-supplied identifier; hidden in the playground. | | `web_search_options` | object | Compatibility search options. | ### Messages parameters | Field | Type | Rule | | ----------------------- | --------------------- | ------------------------------------------------------------------------------- | | `max_tokens` (required) | integer | Positive visible-output limit. Required for Messages. | | `messages` (required) | array | Conversation messages in this format. | | `metadata` | object | Messages metadata object. | | `model` (required) | string | Fixed to `grok-4.7`. | | `stop_sequences` | array or null | Array of stop strings. | | `stream` | boolean or null | Boolean; default false. | | `system` | object or alternative | System string or content blocks. | | `temperature` | number or null | Number from 0 to 2; default 1. | | `tool_choice` | object or alternative | Automatic, disabled, required or a selected tool; syntax depends on the format. | | `tools` | array or null | Tool definitions; at most 350. | | `top_k` | integer or null | Integer; Responses requires at least 1. | | `top_p` | number or null | Number greater than 0 and at most 1; default 1. | {/* grok-parameters:end */} ## Streaming Set `stream` to `true`. Chat emits completion chunks; Responses emits named response events; Messages emits message and content-block events. Read the final usage event as well as text deltas. Tool calls and reasoning can be separate output items; do not reduce the stream to visible text when retaining history. ```json { "model": "grok-4.7", "input": "Explain a mutex in one sentence.", "reasoning": { "effort": "low" }, "max_output_tokens": 128, "store": false, "stream": true } ``` ## Tools and structured output Use the tool definition for your chosen format. Chat uses `response_format`; Responses uses `text.format`. Functions, web search, X search, code interpreter and MCP calls have been exercised with this model. Shell returns a client-executed call; it does not run a command on your computer automatically. The full schema also describes other tool types; a schema entry alone is not evidence that a particular external service is configured. ```json { "model": "grok-4.7", "input": "Use the code interpreter once to compute 13*17. Return the number.", "tools": [{ "type": "code_interpreter" }], "tool_choice": "required", "max_turns": 1, "reasoning": { "effort": "low" }, "max_output_tokens": 32, "store": false } ``` Tool usage is charged separately from tokens. Web search and code interpreter use call counts. X search uses fetched post and profile counts, including repeated fetched items; the number of X search calls is not its billable unit. Inspect `usage.server_side_tool_usage_details` and your account usage records. ## Usage and pricing Prices depend on total input length. Below 200,000 input tokens, use the standard tier. At 200,000 or more, use the long-context tier for the entire request; cached input is included when selecting the tier. `service_tier: "priority"` and `"fast"` double token rates in both tiers. `auto` and `default` select standard service. Tool charges are calculated separately and are not doubled by this token multiplier. | Format | Input accounting | Output accounting | | --------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | Responses | `input_tokens` includes `input_tokens_details.cached_tokens` | `output_tokens` includes reasoning; do not add the reasoning breakdown again | | Chat | `prompt_tokens` includes `prompt_tokens_details.cached_tokens` | xAI reports visible `completion_tokens` separately; total billable output is `total_tokens - prompt_tokens`, including reasoning | | Messages | `input_tokens` excludes `cache_read_input_tokens`; add cache fields to obtain total input | `output_tokens` is the output total | Public responses include usage counters, not monetary cost fields. Your usage records show the final charge. Failed requests are not charged. ## Conversation history and current limits For stateless continuation, send the previous input, every returned output item, and the next user message as the new `input`. With Chat or Messages, send the complete message history in that format. Preserve encrypted reasoning and tool items unchanged where returned. The current service cannot continue using `previous_response_id`, retrieve or delete a stored response, list stored input items, or return deferred Chat completions. `store: true` may be accepted on creation, but that does not establish response storage or retrieval support. File attachments have not worked with the tested inline-text and PDF URL inputs. Image-generation requests returned text without images, and tool search did not complete server-side discovery. These capabilities are not verified as available. Collections search also requires a valid collection resource and has not been verified. Chat ignores `frequency_penalty`, `presence_penalty`, `logit_bias`, `stop`, `logprobs` and `top_logprobs`. Responses ignores `background`, `context_management`, `metadata`, `truncation`, `logprobs` and `top_logprobs`. They are not forwarded or offered as active controls. ## Errors An invalid request returns an error instead of a completed answer. Check the field values and the [public error reference](https://toklab.ai/docs/api/errors). Requests that return an error are not charged. ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/grok-imagine-video-1-5 Grok Imagine Video 1.5 is xAI's video model. One request makes a 6–15 second clip with sound from a prompt, or from a prompt plus one image, at 480p or 720p in 16:9, 9:16 or 1:1. Send the request, keep the returned task ID, and read the finished video from the task. Images go in as URLs. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ------------------------ | --------------- | -------------- | ------------ | | `grok-imagine-video-1-5` | text, one image | `480p`, `720p` | 6–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-imagine-video-1-5", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in, birdsong. No text, no logos.", "resolution": "480p", "duration": 8, "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "grok-imagine-video-1-5", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in, birdsong. No text, no logos.", "resolution": "480p", "duration": 8, "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'grok-imagine-video-1-5', prompt: 'A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in, birdsong. No text, no logos.', resolution: '480p', duration: 8, aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "grok-imagine-video-1-5", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in, birdsong. No text, no logos.", "resolution": "480p", "duration": 8, "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | -------------- | -------- | -------- | -------------------------------------------------------------------------------------- | | `model` | string | required | `grok-imagine-video-1-5` | | `prompt` | string | required | Up to 10,000 characters. Required with an image too. | | `image_urls` | URL list | none | At most one image. With it the clip is image to video; without it, text to video. | | `resolution` | enum | `480p` | `480p` or `720p`. | | `duration` | integer | `8` | 6–15 seconds. | | `aspect_ratio` | enum | `16:9` | `16:9`, `9:16` or `1:1`. With an image, the clip follows the image's shape. | | `audio` | boolean | `true` | Accepted for compatibility. Every clip has sound: `false` does not make a silent clip. | | `fallback` | object | none | `{"enabled": true}` or `{"enabled": false}`. Accepted for compatibility and ignored. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. ## Image to video Pass one image in `image_urls` and describe what happens next in `prompt`. The clip starts from the image and keeps its shape, so a portrait image gives a portrait clip whatever `aspect_ratio` says. ```json { "model": "grok-imagine-video-1-5", "prompt": "The subject slowly turns toward the camera, soft natural light, gentle breeze, quiet room tone.", "image_urls": ["https://example.com/start.png"], "resolution": "720p", "duration": 6 } ``` ## Media inputs The image is a public HTTP(S) URL. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use a JPG or PNG image of 10 MB or less. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. Grok Imagine Video 1.5 is billed per second of video, at a rate set by the resolution: ```text cost = duration × rate per second for the resolution ``` Text to video and image to video cost the same. The duration is known when the request is accepted, so the amount reserved is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "grok-imagine-video-1-5", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "grok-imagine-video-1-5", "status": "completed", "created_at": 1789689600, "finished_at": 1789689720, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests 8-second `720p` clips came back as MP4 (H.264) with an AAC audio track at 1280 × 720 for `16:9`, 720 × 1280 for `9:16` and 720 × 720 for `1:1`, 111–133 seconds after submission. `480p` clips came back in 45–84 seconds. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "grok-imagine-video-1-5", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, place, camera move and light, and name the sounds you want; the audio is generated together with the picture. * Draft at `480p`, then render the final shot at `720p` with the same request. * For vertical video, send `aspect_ratio: "9:16"`, or a portrait image. * Add `no text, no logos` to keep invented marks out. ## Related * [Grok Imagine Video 1.5 pricing](https://toklab.ai/pricing) * [Kling 3.0 Turbo API reference](https://toklab.ai/docs/kling-3-0-turbo) * [Download OpenAPI](https://toklab.ai/docs/grok-imagine-video-1-5.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/grok-imagine-video-1-5.md) --- Source: https://toklab.ai/docs/kimi-k3 Kimi K3 is Moonshot AI's flagship model for long-horizon coding, agents and knowledge work. It always reasons before it answers, and you choose how hard with `reasoning_effort`. Send the official Kimi request to TokLab: change the base URL and the API key, keep the body. ## Model ID | Model ID | Context window | Max output | Reasoning effort | Default effort | | --------- | ---------------- | ---------------------------------- | -------------------- | -------------- | | `kimi-k3` | 1,048,576 tokens | 1,048,576 tokens (default 131,072) | `low`, `high`, `max` | `max` | Input: text and images. Output: text. See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/chat/completions \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k3", "messages": [{"role": "user", "content": "Explain context caching in one sentence."}] }' ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["TOKLAB_API_KEY"], base_url="https://api.toklab.ai/v1", ) completion = client.chat.completions.create( model="kimi-k3", messages=[{"role": "user", "content": "Explain context caching in one sentence."}], ) print(completion.choices[0].message.content) ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.TOKLAB_API_KEY, baseURL: "https://api.toklab.ai/v1", }); const completion = await client.chat.completions.create({ model: "kimi-k3", messages: [{ role: "user", content: "Explain context caching in one sentence." }], }); console.log(completion.choices[0].message.content); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { body := []byte(`{"model": "kimi-k3", "messages": [{"role": "user", "content": "Explain context caching in one sentence."}]}`) req, _ := http.NewRequest("POST", "https://api.toklab.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ## Endpoints | Format | Method and path | Authentication | | ------------------ | ------------------------------------------------ | ----------------------------------------------------------------------------- | | Chat Completions | `POST https://api.toklab.ai/v1/chat/completions` | `Authorization: Bearer ` | | Responses | `POST https://api.toklab.ai/v1/responses` | `Authorization: Bearer ` | | Anthropic Messages | `POST https://api.toklab.ai/v1/messages` | `x-api-key: ` or `Authorization: Bearer `, plus `anthropic-version` | All three return Kimi's official response format, streaming or not. Keep the API key in server-side code. ## Parameters Chat Completions fields: | Name | Type | Required | Default | Notes | | -------------------------------------------------------------------- | ------------------- | -------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------- | | `model` | string | Yes | — | `kimi-k3`. | | `messages` | object\[] | Yes | — | Text messages; images as `image_url` parts (see [Image input](#image-input)). | | `max_completion_tokens` | integer | No | 131072 | Up to 1048576. Includes reasoning tokens. `max_tokens` is the deprecated name for the same limit. | | `reasoning_effort` | enum | No | `max` | `low`, `high` or `max`. Any other value returns 400. | | `stop` | string or string\[] | No | — | Up to 5 sequences. | | `response_format` | object | No | `{"type": "text"}` | `text`, `json_object` or `json_schema` (with `json_schema.name` and `json_schema.schema`). | | `tools` | object\[] | No | — | Function tools. | | `tool_choice` | string or object | No | `auto` | `auto` and `none` are applied. `required` and a named function are accepted but do not force a call. | | `stream` | boolean | No | `false` | Stream server-sent events. | | `stream_options.include_usage` | boolean | No | `false` | Adds the final usage chunk. | | `prompt_cache_options` | object | No | `{"mode": "implicit", "ttl": "5m"}` | `mode`: `implicit`. `ttl`: `5m` or `1h`. | | `prompt_cache_key`, `safety_identifier`, `prediction` | — | No | — | Accepted. | | `logprobs`, `top_logprobs` | — | No | — | Accepted (`top_logprobs` 0–20), but no log probabilities are returned. | | `temperature`, `top_p`, `n`, `presence_penalty`, `frequency_penalty` | — | No | 1.0, 0.95, 1, 0, 0 | Fixed. Any other value returns 400, so leave them out. | ## Reasoning and effort Kimi K3 always reasons; there is no way to turn it off. `reasoning_effort` sets how much: `max` (the default) for the hardest work, `high` for most tasks, `low` for fast, simple steps. The reasoning comes back in `reasoning_content`, next to `content`. Reasoning tokens are billed as output tokens and count toward `max_completion_tokens`. In multi-turn conversations and tool calls, send each assistant message back unchanged, including its `reasoning_content`. ## Image input Kimi K3 takes images as base64 data URIs. A public image URL is not accepted and returns 400, as on Kimi's own API. ```json {"role": "user", "content": [ {"type": "image_url", "image_url": {"url": "data:image/png;base64,"}}, {"type": "text", "text": "Describe this image."} ]} ``` ## Context caching Caching is automatic: a repeated prompt prefix is read from the cache at the lower cached-input rate. `prompt_cache_options.ttl` chooses how long a written prefix stays cached, `5m` (the default) or `1h`; choose `1h` when your requests are more than five minutes apart. `usage.prompt_tokens_details.cached_tokens` reports the tokens read from the cache and `cache_write_tokens` the cache writes billed for the request. ## Billing dimensions See the [current rates on the pricing page](https://toklab.ai/pricing). A request is billed by the tokens it uses: * input tokens, * cached input tokens (`cached_tokens`), * cache-write tokens (`cache_write_tokens`), * output tokens, including reasoning. Prices do not change with context length. The charge is taken from the `usage` reported with the finished response. A request that fails is not charged. Your account's usage records show the exact charge for every request. ## Output A non-streaming Chat Completions request returns: ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1790585961, "model": "kimi-k3", "choices": [{ "index": 0, "finish_reason": "stop", "message": {"role": "assistant", "reasoning_content": "...", "content": "..."} }], "usage": { "prompt_tokens": 90, "completion_tokens": 57, "total_tokens": 147, "cached_tokens": 90, "prompt_tokens_details": {"cached_tokens": 90, "cache_write_tokens": 0} } } ``` With `"stream": true` each chunk carries a `delta` with `reasoning_content` or `content`. With `stream_options.include_usage` a last chunk with an empty `choices` array carries the usage before `data: [DONE]`. ## Responses API and Codex `POST /v1/responses` takes the Responses body: `input`, `instructions`, `max_output_tokens`, `reasoning.effort` (`low`, `high`, `max`), `text.format` (`json_schema`), `tools` (`function` and the `apply_patch` custom tool), `tool_choice`, `stream`, `prompt_cache_options`, `prompt_cache_key` and `safety_identifier`. The reasoning comes back as a `reasoning` item with a `summary_text` part, and a stream carries numbered events from `response.created` to `response.completed`. The API is stateless: `previous_response_id` and `conversation` are ignored, so send the whole conversation in `input`. The `web_search` tool is ignored. To use Kimi K3 in Codex, add a provider to `~/.codex/config.toml` and set `TOKLAB_API_KEY`: ```toml model = "kimi-k3" model_provider = "toklab" model_context_window = 1048576 [model_providers.toklab] name = "TokLab" base_url = "https://api.toklab.ai/v1" env_key = "TOKLAB_API_KEY" wire_api = "responses" ``` ## Anthropic Messages format Code written for the Anthropic Messages API can call Kimi K3 too: send the Messages body to `/v1/messages` with `"model": "kimi-k3"`. `system`, `max_tokens`, `tools`, `tool_choice` (`auto`, `none`) and `output_config.effort` (`low`, `high`, `max`) are applied, and `metadata.user_id` and `cache_control` are accepted. `stop_sequences` (up to 5), `tool_choice` `any` and `output_config.format` are accepted but have no effect. The reasoning comes back as `thinking` blocks. Images go in as `base64` sources. ## Errors Errors use `{"error": {"code": ..., "message": "..."}}` (the Messages endpoint uses Anthropic's error shape). The `code` is a code from the [common error catalog](https://toklab.ai/docs/api/errors). Failed requests are not charged. ## Tips * Start with `high` effort and move to `max` only for the hardest problems; `low` suits quick, simple steps. * Set `max_completion_tokens` high enough for the reasoning as well as the answer: it is one budget for both. * Keep long, reused context at the start of the prompt so later requests read it from the cache, and use the `1h` TTL when requests are spread out. ## Related * [Kimi K3 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/kimi-k3.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/kimi-k3.md) ## Optional LLM group The groups you can use depend on your account permissions and the model. The [pricing page](https://toklab.ai/pricing) lists each group's prices. API calls keep your API key and model ID. To select a group, send its exact name in the optional `X-SeedRouter-Group` request header, or append it to the model ID as `model:` (see [Model tiers](https://toklab.ai/docs/api/model-tiers)). Replace `GROUP_NAME` below with one of your groups. Omit the header or use `auto` to keep the key's default behavior. ```http X-SeedRouter-Group: GROUP_NAME ``` A restricted API key may have fewer group options than your account. Requests use the selected group's pricing and do not switch to another group if it is unavailable. This option supports HTTP LLM calls, including SSE; it does not apply to WebSocket, image or video calls. To see the groups your key can use, call `GET /v1/models`: it lists `model:` next to the model ID for every model your key can call in more than one group. --- Source: https://toklab.ai/docs/kimi-k3-1-pro Use the public model ID `kimi-k3.1-pro`. Live prices are on the [pricing page](https://toklab.ai/pricing). Download the [OpenAPI specification](https://toklab.ai/docs/kimi-k3-1-pro.openapi.json) for complete nested request and response schemas. ## Quick start ```bash curl https://api.toklab.ai/v1/chat/completions \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model":"kimi-k3.1-pro", "messages":[{"role":"user","content":"How can an idempotency key prevent a duplicate payment?"}], "max_completion_tokens":2048, "reasoning_effort":"low" }' ``` ```python import json import os import urllib.request request = urllib.request.Request( "https://api.toklab.ai/v1/chat/completions", headers={ "Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}", "Content-Type": "application/json", }, data=json.dumps({ "model": "kimi-k3.1-pro", "messages": [{"role": "user", "content": "How can an idempotency key prevent a duplicate payment?"}], "max_completion_tokens": 2048, "reasoning_effort": "low", }).encode(), method="POST", ) with urllib.request.urlopen(request, timeout=120) as response: result = json.load(response) print(result["choices"][0]["message"]["content"]) ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/chat/completions', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'kimi-k3.1-pro', messages: [{ role: 'user', content: 'How can an idempotency key prevent a duplicate payment?' }], max_completion_tokens: 2048, reasoning_effort: 'low', }), signal: AbortSignal.timeout(120000), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const result = await response.json(); console.log(result.choices[0].message.content); ``` ```go package main import ( "fmt" "io" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "kimi-k3.1-pro", "messages": [{"role": "user", "content": "How can an idempotency key prevent a duplicate payment?"}], "max_completion_tokens": 2048, "reasoning_effort": "low" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/chat/completions", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 120 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } data, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(data)) } ``` ## Native formats | Format | Endpoint | Required fields | | ---------------- | --------------------------- | --------------------------------- | | Chat Completions | `POST /v1/chat/completions` | `model`, `messages` | | Responses | `POST /v1/responses` | `model`, `input` | | Messages | `POST /v1/messages` | `model`, `messages`, `max_tokens` | Use `Authorization: Bearer $TOKLAB_API_KEY`. Messages also uses `anthropic-version: 2023-06-01`. Each format returns native JSON or SSE events. Responses is stateless: replay complete history; `previous_response_id` is not a supported request field. ## Request parameters Explicit false and zero are preserved where valid. Omitted does not mean nullable. Unknown top-level extensions are discarded; invalid official fields are rejected. Nested tool schemas and returned history remain intact. ### Chat Completions | Field | Type | Required | Default / range | | ----------------------- | ------- | -------- | -------------------------------------- | | `logprobs` | boolean | No | default false | | `top_logprobs` | integer | No | 0–20; requires logprobs=true | | `prediction` | object | No | Omitted unless supplied | | `max_tokens` | integer | No | 1–1048576 | | `max_completion_tokens` | integer | No | 1–1048576; default 131072 | | `response_format` | object | No | Omitted unless supplied | | `stop` | union | No | ≤5 strings; ≤32 UTF-8 bytes each | | `stream` | boolean | No | default false | | `stream_options` | object | No | Omitted unless supplied | | `tools` | array | No | Omitted unless supplied | | `prompt_cache_key` | string | No | Omitted unless supplied | | `prompt_cache_options` | object | No | Omitted unless supplied | | `safety_identifier` | string | No | Omitted unless supplied | | `tool_choice` | union | No | Omitted unless supplied | | `messages` | array | Yes | Omitted unless supplied | | `reasoning_effort` | string | No | low, high, max; default "max" | | `model` | string | Yes | kimi-k3.1-pro; default "kimi-k3.1-pro" | | `temperature` | number | No | 1 | | `top_p` | number | No | 0.95 | | `n` | integer | No | 1 | | `frequency_penalty` | number | No | 0 | | `presence_penalty` | number | No | 0 | ### Responses | Field | Type | Required | Default / range | | ---------------------- | ------- | -------- | -------------------------------------- | | `model` | string | Yes | kimi-k3.1-pro; default "kimi-k3.1-pro" | | `input` | union | Yes | Omitted unless supplied | | `instructions` | string | No | Omitted unless supplied | | `stream` | boolean | No | default false | | `max_output_tokens` | integer | No | 1–1048576; default 131072 | | `reasoning` | object | No | Omitted unless supplied | | `text` | object | No | Omitted unless supplied | | `tools` | array | No | Omitted unless supplied | | `tool_choice` | object | No | Omitted unless supplied | | `include` | array | No | Omitted unless supplied | | `prompt_cache_key` | string | No | Omitted unless supplied | | `prompt_cache_options` | object | No | Omitted unless supplied | | `safety_identifier` | string | No | Omitted unless supplied | ### Messages | Field | Type | Required | Default / range | | ---------------- | ------- | -------- | -------------------------------------- | | `model` | string | Yes | kimi-k3.1-pro; default "kimi-k3.1-pro" | | `messages` | array | Yes | Omitted unless supplied | | `max_tokens` | integer | Yes | 1–1048576 | | `system` | union | No | Omitted unless supplied | | `stream` | boolean | No | default false | | `stop_sequences` | array | No | ≤5 strings; ≤32 UTF-8 bytes each | | `tools` | array | No | Omitted unless supplied | | `tool_choice` | object | No | Omitted unless supplied | | `metadata` | object | No | Omitted unless supplied | | `cache_control` | object | No | Omitted unless supplied | | `output_config` | object | No | Omitted unless supplied | Chat has 22 top-level fields: model, five fixed sampling fields and 16 variable inputs. Responses has model plus 12 inputs; Messages has model plus 10 inputs. ### Reasoning and output limits Thinking is always enabled. Chat `reasoning_effort`, Responses `reasoning.effort` and Messages `output_config.effort` accept `low`, `high` or `max`; default `max`. All output limits include reasoning. Chat and Responses default to 131,072 output tokens, with a maximum of 1,048,576. Messages requires a positive `max_tokens`. Chat accepts deprecated `max_tokens`; prefer `max_completion_tokens` for new integrations. The context window is 1,048,576 tokens. Input itself must fit inside it. When input plus the generation budget exceeds the window, the service can reduce the budget to the remaining space. A small output cap may stop before any visible answer appears. Chat sampling is fixed: `temperature:1`, `top_p:0.95`, `n:1`, `frequency_penalty:0`, `presence_penalty:0`. Other values are invalid. Stop sequences match exact text and are excluded from the answer. Their 32-byte limit counts UTF-8 bytes, not characters. ### Structured output and predictions Chat accepts `response_format.type` of `text`, `json_object` or `json_schema`. JSON mode also needs a prompt asking for JSON. JSON Schema requires `json_schema.name` and `json_schema.schema`; `strict` defaults to true. Responses uses `text.format` with `type:json_schema`, `schema`, optional `name` and `strict`. Messages uses `output_config.format` with `type:json_schema` and `schema`. Follow Moonshot Flavored JSON Schema; do not assume every general JSON Schema extension is enforced. Validate completed output in your application. Chat predicted output uses `prediction:{type:"content",content:...}`. Content is a string or text-only parts. Use it for mostly known output, such as a file receiving a small edit. ### Tools and preserved conversation history Chat tools use `type:function` with `function.name` and `function.parameters`. Optional fields include `description` and `strict` (default true). Names match `^[a-zA-Z_][a-zA-Z0-9-_]{0,127}$`. Tool choice supports `auto`, `none` and `required`; required needs at least one available tool. Forcing a named function conflicts with always-on thinking. A dynamic Chat tool message is `{role:"system",tools:[...]}` without content. Keep these messages in the conversation. Append the complete assistant reply, including `reasoning_content` and `tool_calls`, then return each tool result as a `role:tool` message with the matching `tool_call_id`. Assistant tool replies can carry null content. Other message roles still require content. Responses supports native function, namespace, `apply_patch` custom and `web_search` tool definitions with `tool_choice:"auto"`. Return `function_call_output` or `custom_tool_call_output` items with matching call IDs. The include values `web_search_call.results` and `web_search_call.action.sources` affect web-search output only. Messages supports native tool definitions and tool choice objects with type `auto`, `any` or `none`. Preserve assistant thinking blocks and their signatures. Return tool-result blocks inside user messages. Your application validates arguments, executes custom functions and controls external actions. Chat Partial Mode sets `partial:true` only on the final assistant message. Messages continues a final assistant message directly. Do not rebuild history from visible answer text alone. ### Media constraints Chat accepts text, `image_url` and `video_url` content blocks. Use base64 data URLs or accepted `ms://` references; arbitrary public media URLs are unsupported. Image formats: JPEG, PNG, GIF, WebP, BMP, HEIC and HEIF. Video formats: MP4, MPEG, MOV, AVI, FLV, MPG, WebM, WMV and 3GPP. The official guide specifies a total request-body limit of 100M, with no separate image-count cap. 4K images and Full HD video are recommendations, not required limits. Responses uses `input_image.image_url` with a data URL. Messages uses an image source such as `{type:"base64",media_type:"image/png",data:"..."}`, or type `url` with an accepted `ms://` reference. Messages inline image types are JPEG, PNG, GIF and WebP. These formats do not inherit Chat's video block by implication; use their dedicated schemas. Use native conversation fields or the JSON editor for video blocks and file references. File upload/management is outside these generation endpoints. A file ID created with another account is not necessarily usable. ### Caching and usage Chat and Responses use `prompt_cache_key` and `prompt_cache_options:{mode:"implicit",ttl:"5m"}`. TTL accepts `5m` or `1h`, default 5 minutes. Messages uses top-level `cache_control:{type:"ephemeral",ttl:"5m"}` and optional `metadata.user_id`. Nested Messages cache-control markers are ignored. Content-level `prompt_cache_breakpoint` is invalid. An existing cached prefix retains its original TTL when refreshed. Requesting a different lifetime does not prove that it applied. Chat's official cache-write headers report actual 5-minute and 1-hour counts. Responses can return applied `prompt_cache_options`; Messages reports both TTL counters in `usage.cache_creation`. | Format | Total input | Cache read | Cache write | | --------- | ---------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------ | | Chat | `usage.prompt_tokens` | `prompt_tokens_details.cached_tokens` | `prompt_tokens_details.cache_write_tokens` | | Responses | `usage.input_tokens` | `input_tokens_details.cached_tokens` | `input_tokens_details.cache_write_tokens` | | Messages | `input_tokens + cache_read_input_tokens + cache_creation_input_tokens` | `cache_read_input_tokens` | `cache_creation_input_tokens` | Chat and Responses input totals already include cache reads and writes. These categories and the uncached remainder are disjoint; do not add cache tokens twice. Output includes reasoning. Messages separates writes into `ephemeral_5m_input_tokens` and `ephemeral_1h_input_tokens`. See [live rates](https://toklab.ai/pricing); public generation responses do not contain monetary charges. ### Streaming and completion Set `stream:true`. Chat emits data chunks and `[DONE]`; `stream_options.include_usage:true` requests the final usage chunk. Responses uses named events such as `response.output_text.delta`, `response.completed` and `response.incomplete`. Messages uses `message_start`, content-block events, `message_delta` and `message_stop`. A closed connection alone does not prove completion. Check native finish reasons and terminal status. An interrupted stream may lack final usage. Stopping a reader does not guarantee generation cancellation. ## Official references Checked on October 25, 2026: [Kimi K3.1 Pro guide](https://platform.kimi.ai/docs/guide/kimi-k3-1-pro-quickstart), [Chat](https://platform.kimi.ai/docs/api/chat), [Responses](https://platform.kimi.ai/docs/api/responses), [Messages](https://platform.kimi.ai/docs/api/messages), [vision](https://platform.kimi.ai/docs/guide/use-kimi-vision-model) and [caching](https://platform.kimi.ai/docs/guide/context-caching). --- Source: https://toklab.ai/docs/kling-3-0 Kling 3.0 is Kuaishou's video generation model. One request makes a 3–15 second clip from a prompt, or from a first frame and an optional last frame, at three quality modes (`std`, `pro`, `4K`), with native sound when you ask for it. A clip can also be a sequence of up to five shots, each with its own prompt and length. Send the request, keep the returned task ID, and read the finished video from the task. Images go in as URLs. ## Model IDs | Model ID | Inputs | Modes | Length | | ----------- | ------------------------------------ | ------------------ | ------------ | | `kling-3-0` | text, first and last frame, elements | `std`, `pro`, `4K` | 3–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-3-0", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist on the water, slow push-in, no text, no logos.", "mode": "pro", "duration": 5, "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "kling-3-0", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist on the water, slow push-in, no text, no logos.", "mode": "pro", "duration": 5, "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'kling-3-0', prompt: 'A red paper boat drifting on a calm pond at sunrise, soft mist on the water, slow push-in, no text, no logos.', mode: 'pro', duration: 5, aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "kling-3-0", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist on the water, slow push-in, no text, no logos.", "mode": "pro", "duration": 5, "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | ---------------- | ------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `kling-3-0` | | `prompt` | string | required for a single shot | Up to 2,500 characters. Optional in multi-shot mode. | | `image_urls` | array of URLs | none | Up to 2 images: the first is the first frame, the second the last frame. Without images the clip is text to video. | | `mode` | enum | `pro` | `std`, `pro` or `4K` (uppercase K). | | `duration` | integer | `5` | 3–15 seconds. | | `aspect_ratio` | enum | `16:9` | `16:9`, `9:16` or `1:1`. | | `sound` | boolean | `false` | Generate native sound with the video. | | `multi_shots` | boolean | `false` | Make the clip from the shots in `multi_prompt`. | | `multi_prompt` | array | none | Up to 5 shots, each `{"prompt", "duration"}`: a prompt of up to 500 characters and a whole number of seconds from 1 to 12. Required when `multi_shots` is `true`. | | `kling_elements` | array | none | Up to 3 elements, each `{"name", "description", "element_input_urls"}` with 2–4 image URLs. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. ## Multi-shot clips Set `multi_shots` to `true` and describe each shot in `multi_prompt`. The shot durations must add up to 3–15 seconds; that sum is the clip length, and `duration` is not used. `prompt` can be left out or used for what every shot shares. ```json { "model": "kling-3-0", "mode": "pro", "multi_shots": true, "multi_prompt": [ {"prompt": "A red paper boat on a calm pond at sunrise, wide shot", "duration": 3}, {"prompt": "The boat drifts under a small wooden bridge, low angle", "duration": 3} ] } ``` ## Elements An element is a subject the model keeps consistent across the clip: a person, a product or a character. Give it a `name`, a short `description` and 2–4 images of it, then mention it by name in the prompt (for example `@hero`). ```json { "model": "kling-3-0", "prompt": "@hero slowly turns toward the camera in soft window light", "kling_elements": [ { "name": "hero", "description": "a young woman with short black hair and a yellow raincoat", "element_input_urls": ["https://example.com/hero-front.png", "https://example.com/hero-side.png"] } ] } ``` ## Media inputs Every image is a public HTTP(S) URL. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use JPG or PNG images of 10 MB or less. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. Kling 3.0 is billed per second of video, at a rate set by the mode and by whether `sound` is on: ```text billed seconds = duration (single shot) billed seconds = Σ multi_prompt[].duration (multi_shots: true) cost = billed seconds × rate per second ``` The billed seconds are known when the request is accepted, so the amount reserved is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "kling-3-0", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "kling-3-0", "status": "completed", "created_at": 1789689600, "finished_at": 1789689710, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests a 3-second `std` clip came back as MP4 (H.264) at 1280 × 720, and a 5-second `pro` clip with `sound` at 1920 × 1080 with an audio track, each in about two to three minutes. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "kling-3-0", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, place, camera move and light in one sentence each; Kling follows camera language such as "slow push-in" and "low angle". * Draft in `std`, then render the final shot in `pro` or `4K` with the same request. * Use a first and a last frame to control where a shot starts and ends. * Split a scene into shots with `multi_prompt` instead of describing several cuts in one prompt. * Add `no text, no logos` to keep invented marks out. ## Related * [Kling 3.0 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/kling-3-0.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/kling-3-0.md) --- Source: https://toklab.ai/docs/kling-3-0-turbo Kling 3.0 Turbo is a video model in Kuaishou's Kling 3.0 family. One request makes a 3–15 second clip with sound from a prompt, or from a prompt plus a first frame, at 720p or 1080p. Send the request, keep the returned task ID, and read the finished video from the task. Images go in as URLs. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ----------------- | ----------------- | --------------- | ------------ | | `kling-3-0-turbo` | text, first frame | `720p`, `1080p` | 3–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-3-0-turbo", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "kling-3-0-turbo", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'kling-3-0-turbo', prompt: 'A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.', resolution: '720p', duration: 5, aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "kling-3-0-turbo", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | ------------------- | ------- | -------- | ------------------------------------------------------------------------------------------ | | `model` | string | required | `kling-3-0-turbo` | | `prompt` | string | required | Up to 3,072 characters, or 2,500 with a first frame. Required with a first frame too. | | `first_frame_image` | URL | none | The clip's first frame. Without it the clip is text to video. | | `resolution` | enum | `720p` | `720p` or `1080p`. | | `duration` | integer | `5` | 3–15 seconds. | | `aspect_ratio` | enum | `16:9` | `16:9`, `9:16` or `1:1`. Text to video only: with a first frame, the frame sets the shape. | | `watermark` | boolean | none | `true` adds a watermark. Left out, the clip has none. | Every clip comes with sound; there is no sound setting. The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. ## Image to video Pass a first frame in `first_frame_image` and describe what happens next in `prompt`. The clip opens on the frame and takes its shape, so `aspect_ratio` is not used. ```json { "model": "kling-3-0-turbo", "prompt": "The subject slowly turns toward the camera, soft natural light, gentle breeze.", "first_frame_image": "https://example.com/frame.png", "resolution": "1080p", "duration": 5 } ``` ## Media inputs The first frame is a public HTTP(S) URL. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use a JPG or PNG image of 10 MB or less. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. Kling 3.0 Turbo is billed per second of video, at a rate set by the resolution: ```text cost = duration × rate per second for the resolution ``` The duration is known when the request is accepted, so the amount reserved is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "kling-3-0-turbo", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "kling-3-0-turbo", "status": "completed", "created_at": 1789689600, "finished_at": 1789689710, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests 3-second `720p` clips came back as MP4 (H.264) at 1280 × 720 and 5-second `1080p` clips at 1920 × 1080, all with a stereo audio track, between 54 seconds and about 5 minutes 20 seconds after submission. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "kling-3-0-turbo", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, place, camera move and light in one sentence each; camera language such as "slow push-in" and "low angle" is followed. * Draft at `720p`, then render the final shot at `1080p` with the same request. * With a first frame, describe only what moves: the frame already sets the scene. * Add `no text, no logos` to keep invented marks out. ## Related * [Kling 3.0 Turbo pricing](https://toklab.ai/pricing) * [Kling 3.0 API reference](https://toklab.ai/docs/kling-3-0) * [Download OpenAPI](https://toklab.ai/docs/kling-3-0-turbo.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/kling-3-0-turbo.md) --- Source: https://toklab.ai/docs/kling-4-0 Kling 4.0 is Kuaishou's video model announced in September 2026. One model ID covers five modes: text to video, image to video with up to 10 frames, reference-based generation from images, videos and audio, video editing, and video extension. Every clip is 3–30 seconds at 720p or 1080p with stereo sound. Send the request, keep the returned task ID, and read the finished video from the task. Media goes in as URLs. ## Model IDs | Model ID | Modes | Resolutions | Length | | ----------- | ------------------------------------ | --------------- | ------------ | | `kling-4-0` | text, image, reference, edit, extend | `720p`, `1080p` | 3–30 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-4-0", "prompt": "A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "kling-4-0", "prompt": "A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'kling-4-0', prompt: 'A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.', resolution: '720p', duration: 5, aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "kling-4-0", "prompt": "A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | -------------------------- | ----------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `kling-4-0` | | `prompt` | string | required | Optional for image to video only. Mention references as `@Image1`, `@Video1`, `@Audio1`, numbered from 1 in each list. | | `duration` | integer | `5` | 3–30 seconds. Edit: left out, the output follows the input video. Extend: the length of the new part. | | `resolution` | enum | `720p` | `720p` or `1080p`. | | `aspect_ratio` | enum | by mode | `16:9`, `9:16`, `1:1`, `21:9`; `auto` for reference mode only. Defaults: text `16:9`, image the first frame's shape, reference `auto`, edit the input video's shape. Not accepted with extend. | | `image_urls` | URL list | none | Image to video: up to 2, the first then the last frame. Reference (with `omni_reference_task_type: "reference"`) and edit: up to 10 reference images. | | `image_with_roles` | object list | none | `{"url", "role"}` with role `first_frame`, `last_frame`, `keyframe` (or `middle_frame`) or `reference_image`. Exactly 1 first frame, up to 8 keyframes used in order, 10 frames in total. | | `first_frame_image` | URL | none | The first frame for image to video. | | `last_frame_image` | URL | none | The last frame for image to video, or the target last frame for extend. | | `video_urls` | URL list | none | Reference videos: up to 5, 30 seconds used in total. For edit or extend, exactly 1 in place of `video_url`. | | `video_url` | URL | none | The input video for edit or extend; requires `omni_reference_task_type` `edit` or `extend`. | | `audio_urls` | URL list | none | Reference audio: up to 3 clips of 5–30 seconds each. | | `omni_reference_task_type` | enum | `auto` | `auto`, `reference`, `edit` or `extend`. | | `audio_setting` | enum | by mode | `origin` keeps the input video's audio, `auto` regenerates it. Edit keeps it by default; reference with videos regenerates it by default. Not accepted with extend. | Every clip comes with stereo sound; there is no sound switch. There is no `mode`, `negative_prompt`, `watermark` or multi-shot field. The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. ## Modes The mode follows the media you send and `omni_reference_task_type`: | Mode | How to select it | | -------------- | -------------------------------------------------------------------------------------------------- | | Text to video | No media. | | Image to video | A first frame, optionally a last frame and keyframes. | | Reference | `video_urls`, `audio_urls` or `reference_image` roles, or `omni_reference_task_type: "reference"`. | | Edit | `omni_reference_task_type: "edit"` and one input video. | | Extend | `omni_reference_task_type: "extend"` and one input video. | Frames and reference media cannot be mixed in one request. Next to reference videos or audio, `image_urls` count as reference images only with `omni_reference_task_type: "reference"`; use `reference_image` roles otherwise. A `video_url` without `edit` or `extend` is rejected. ### Keyframes ```json { "model": "kling-4-0", "prompt": "A girl walks from the window to the door, then looks back and smiles", "image_with_roles": [ {"url": "https://example.com/1.png", "role": "first_frame"}, {"url": "https://example.com/2.png", "role": "keyframe"}, {"url": "https://example.com/3.png", "role": "last_frame"} ], "duration": 10 } ``` ### Reference ```json { "model": "kling-4-0", "prompt": "The woman from @Image1 walks along the beach with the camera movement of @Video1", "image_with_roles": [{"url": "https://example.com/woman.png", "role": "reference_image"}], "video_urls": ["https://example.com/camera.mp4"], "aspect_ratio": "auto", "duration": 5 } ``` ### Edit ```json { "model": "kling-4-0", "prompt": "Change the scene to a snowy winter evening", "omni_reference_task_type": "edit", "video_url": "https://example.com/in.mp4" } ``` The input video must be at least 3 seconds; only its first 30 seconds are used. Without `duration`, the output follows the input video. ### Extend ```json { "model": "kling-4-0", "prompt": "The camera keeps moving forward as the sky grows darker", "omni_reference_task_type": "extend", "video_url": "https://example.com/in.mp4", "duration": 5 } ``` Extension continues from the input video's last frame and returns the original plus the new part. Add `last_frame_image` to choose where it ends. ## Media inputs Images, videos and audio are public HTTP(S) URLs. Base64 data URIs are not accepted: upload the files to your own storage and pass their URLs. Images, videos and audio together are at most 15 reference files. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. Kling 4.0 is billed per second of video, at a rate set by the resolution: ```text text, image, reference without videos: cost = duration × standard rate extend: cost = new seconds × standard rate edit, reference with videos: cost = (output + max(output, input)) × video-input rate ``` `input` is the summed length of the input videos, rounded up to whole seconds and capped at 30. It is measured when the request is accepted, so the amount reserved is the amount charged. A video whose length cannot be read is rejected before anything is charged. Example: editing a 5.2-second video into a 3-second result bills 3 + 6 = 9 seconds. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "kling-4-0", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "kling-4-0", "status": "completed", "created_at": 1789689600, "finished_at": 1789689800, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests 3-second `720p` clips came back as MP4 (H.264) at 1280 × 720 with a stereo AAC track, 2 min 41 s to 4 min 22 s after submission. An extended 5.2-second video came back 8.1 seconds long. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "kling-4-0", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, place, camera move, light and sound; the clip's audio follows the prompt. * Draft at `720p`, then render the final shot at `1080p` with the same request. * Give longer clips keyframes so the scene moves where you want it. * Add `no text, no logos` to keep invented marks out. ## Related * [Kling 4.0 pricing](https://toklab.ai/pricing) * [Kling 3.0 API reference](https://toklab.ai/docs/kling-3-0) * [Download OpenAPI](https://toklab.ai/docs/kling-4-0.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/kling-4-0.md) --- Source: https://toklab.ai/docs/midjourney This reference describes the implemented API contract. Paid integration checks on October 18, 2026 completed imagine requests for all nine listed versions, V8.2 Raw on/off, HD, Draft, V7 Omni Reference, describe, grid selection, and V6.1 inpaint → modal. These checks do not certify every parameter combination or visual effect. V8.2 HD+Draft failed in two checks but remains available; a tested remix failed because its original execution context lacked capacity. Unsupported combinations return an error before submission. Failed requests are not charged. ## Start with one image request Set `TOKLAB_API_KEY` on your server. Submit **once**, save the returned public task ID, then poll that ID. The simplest request needs only `model` and `prompt`. Its default action is `imagine` and its default speed is `fast`. ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"midjourney-v8.2","prompt":"A red paper boat on a calm pond at sunrise"}' ``` Copy `id` from the response into `TASK_ID`. Keep calling GET until `status` is `completed` or `failed`: ```bash TASK_ID='task_ID_FROM_THE_RESPONSE' curl "https://api.toklab.ai/v1/tasks/$TASK_ID" \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` Read completed images from `output.data[].url`. If a POST times out or its outcome is uncertain, check task history instead of repeating it. A poll timeout does not cancel the task or justify a second POST. ### Runnable Python example Download the [complete Python submit-and-poll example](https://toklab.ai/examples/midjourney-v8-2.py). It uses only Python's standard library and saves the task ID to a local file. Save the JSON request above as `request.json`, then run: ```bash python3 midjourney-v8-2.py submit request.json --state image-task.json python3 midjourney-v8-2.py poll --state image-task.json ``` The submit command refuses to overwrite its state file. Resume a long-running task by running `poll` again with the same file. The script never retries POST automatically. Change the `model` and parameters in `request.json` using the version examples below; use a new state-file name only for an intentionally new generation. ## Choose a model version These tables describe the **implemented API contract**, based on the API services' own documented inputs and exclusions. A field listed in a general API parameter table is accepted where a compatible request can be executed; that does **not** establish its visual effect on every model version. Documented support and live verification are separate. The API never changes the requested version or silently upgrades Relax to Fast. | Model ID | Generation speeds | Quality values | HD / Draft | Character / Omni reference | Depth / personalization | | ----------------- | ------------------ | ------------------ | ------------------------------------- | -------------------------------------- | ----------------------------------------------- | | `midjourney-v8.2` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2 | HD; Draft on compatible Fast requests | `cref`; no `oref` | Depth; explicit profile conditionally available | | `midjourney-v8.1` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2 | HD; Draft on compatible Fast requests | `cref`; no `oref` | Depth; explicit profile conditionally available | | `midjourney-v7` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2, 4 | HD is a no-op; Draft supported | `cref`; `oref` conditionally available | Depth; explicit profile conditionally available | | `midjourney-v6.1` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2, 4 | HD is a no-op; no Draft | `cref`; no `oref` | Depth; explicit profile conditionally available | | `midjourney-v6` | Fast, Turbo | 0.25, 0.5, 1, 2, 4 | HD is a no-op; no Draft | `cref`; no `oref` | No depth; explicit profile | | `midjourney-v5.2` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2 | Neither | `cref`; no `oref` | Depth; no profile | | `midjourney-v5.1` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2 | Neither | `cref`; no `oref` | Depth; no profile | | `niji-v7` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2 | Neither | `cref`; no `oref` | Depth; no profile | | `niji-v6` | Relax, Fast, Turbo | 0.25, 0.5, 1, 2, 4 | HD is a no-op; no Draft | `cref`; no `oref` | Depth; explicit profile conditionally available | All nine versions accept Raw, tile, `iw` 0–3, one style-reference URL, and the common numeric controls below. Character/style/depth inputs listed in the general API table have not been proven effective on every version. Never substitute one reference type for another. “Conditionally available” means the **complete combination** must be executable. V8 Draft, quality 4, Omni Reference and explicit profiles cannot satisfy `nsfw_check: true`; they require API or administrator access. V6 also cannot satisfy that additional check. V8 character/depth/quality inputs can be combined with the extra check, but cannot be combined with fields that require an incompatible request path. For example, V8 `quality: 1` plus `stop: 100` currently has no compatible execution path, even though each field is individually supported. ### Defaults and common bounds New generations default only `action` to `imagine` and `speed` to `fast`. Version and family come from `model`. Omitted generation fields remain omitted; a billing label of quality `1` does not insert `quality` into the image request. Explicit zero and false are preserved. All numeric parameters stay within ±9,007,199,254,740,991 as a JSON/JavaScript transport safeguard; this is not a claimed model-specific range. | Field | Validation and availability | Omitted value | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | `prompt` | A text description is required for imagine, including when images are supplied; no `{permutations}` | No text | | `size` | Positive finite `W:H`; decimal ratios have narrower availability. V6 requires integer ratios no wider than 14:1 or 1:14 | No aspect-ratio setting added | | `seed` | Finite JSON number within ±9,007,199,254,740,991 for exact transport. Integers outside 0–4,294,967,295 have narrower availability; fractional seeds require that nonnegative 32-bit range | No seed added | | `stylize` | Number 0–1,000 | Model default retained | | `chaos` | Number 0–100 | Model default retained | | `weird` | Number 0–3,000 | Model default retained | | `raw`, `tile` | Boolean; false never becomes a literal `--raw false` or `--tile false` | No flag added | | `negative_prompt` | Nonempty text; no embedded flags or permutations | No exclusions | | `image_urls` | Public HTTP(S) URLs; order and duplicates retained | No reference images | | `metadata` | JSON object; not an image-generation setting | No metadata | Fractional `seed`, `stylize`, `chaos`, `weird`, `cw`, `sw` and `stop` values require a compatible request without `nsfw_check: true`. Whole-number `sw` values from 0–1,000 have wider availability; other finite style weights are supported only on narrower combinations. These distinctions come from API number/integer contracts, not inferred model capabilities. ### Midjourney V8.2 and V8.1 Applies to **`midjourney-v8.2` and `midjourney-v8.1`**. Standard generation supports Relax, Fast and Turbo. Quality is optional and accepts 0.25, 0.5, 1 or 2. Character reference (`cref`/`cw`), style reference (`sref`/`sw`) and depth reference (`dref`/`dw`) are documented inputs; their effect with each version is still to be verified. `iw` is 0–3. HD is a definition switch, separate from an upscale action. **HD + Turbo remains unavailable because its price is not configured.** Fast HD has a compatible request path. Integer ratios no wider than 4:1 work across the available HD contracts; other positive ratios have narrower availability and need live verification. Draft has a Fast-only path with up to 24 image choices and cannot satisfy the extra content check. HD + Draft is a separate configured mode, still awaiting combination verification. `stop` 10–100 and a nonempty personalization `profile` have a Fast-only path without the extra content check. That path does not accept `quality` or `cref`, so combining those fields fails before submission. `style: "raw"` is normalized to Raw; other style strings have a separate compatible path and are not assumed to be visually effective. `oref`/`ow` are unavailable on V8. Explicit `sd: true`, `sv`, `exp`, and `edit` currently have no established execution contract. `edit` is not an alias for image prompts, inpaint, or modal. V8 variation, grid selection, reroll and remix depend on the parent's available actions. Real upscale mode semantics are unverified. Zoom and pan have narrower parent-dependent Fast paths without the extra content check; inpaint is unavailable. ### Midjourney V7 Applies to **`midjourney-v7`**. Quality accepts 0.25, 0.5, 1, 2 or 4; quality 4 requires a non-Relax request without the extra content check. Character and depth references use a different compatible request path from Omni Reference. Ordinary image prompts use `iw` 0–3. Omni Reference uses one `oref` URL and optional finite `ow`. `ow` requires the URL so the correct reference price can be determined. Quality 4 with Omni Reference is accepted by the documented contract. **Omni Reference + Draft remains blocked because the combined price is unresolved**, not because a model-level incompatibility has been established. Draft is supported. `hd: true` is accepted only as a documented no-op on the compatible path: it leaves standard output unchanged and adds no HD charge. Stop and explicit profiles require a non-Relax request without the extra check. `sv`, `exp`, `edit`, and explicit `sd: true` remain unavailable. See the action matrix for parent-specific operations. ### Midjourney V6.1, V6 and Niji 6 Applies to **`midjourney-v6.1`, `midjourney-v6`, and `niji-v6`**. Quality accepts 0.25, 0.5, 1, 2 or 4. `iw` accepts 0–3; character weight `cw` accepts 0–100. Character and style references each use one HTTP(S) URL. Stop accepts 10–100. No generation default is inferred from the selected version. V6.1 and Niji 6 support Relax/Fast/Turbo and depth inputs on compatible requests; V6 has only Fast/Turbo generation, no depth input, integer ratios up to 14:1, and no extra content-check path. All three accept a nonempty profile on compatible non-Relax requests. Quality 4 and fractional numeric controls have narrower availability. `hd: true` is a standard-output no-op with no HD charge. Draft and Omni Reference are unavailable. For Niji 6, a negative prompt cannot be combined with fields that need its alternate request path, such as quality 4 or a profile. V6.1 and Niji 6 can begin inpaint when a valid parent permits it; V6 cannot. V6 parent actions require Fast. Real upscales use `subtle`/`creative`, not V5's `2x`/`4x`; available parent buttons remain authoritative. ### Midjourney V5.2 and V5.1 Applies to **`midjourney-v5.2` and `midjourney-v5.1`**. Both accept quality 0.25, 0.5, 1 or 2, `iw` 0–3, integer `stop` 10–100, character/style/depth references, Raw, tile and style strings. These inputs appear in the general API contract; version-specific visual effects remain unverified. Numeric controls documented as integers must be whole numbers here, including seed, stylize, chaos, weird, cw, sw and stop. Style weight is 0–1,000. HD, Draft, Omni Reference, personalization and quality 4 have no current compatible path. Explicit `sd: true`, `sv`, `exp`, `edit`, repeat and prompt permutations are unavailable. Parent real upscales use `2x`/`4x` and require the corresponding returned operation. They are distinct from free grid selection. ### Niji 7 Applies to **`niji-v7`**. It has its own model ID and availability rules. Quality accepts 0.25, 0.5, 1 or 2, and image weight accepts 0–3. Character/style/depth references are listed in the general API input table; effects with Niji 7 remain to be verified. Numeric integer fields and style-weight bounds match the V5.1/V5.2 request path above. Stop, quality 4, HD, Draft, Omni Reference and personalization have no current compatible path. Niji Draft output count and pricing have not been established. V8 remix is not an available Niji 7 action. Real upscale command semantics are unverified; grid selection and other actions still depend on a valid parent. ### One valid generation example per model These JSON bodies pass local model validation and have an implemented execution candidate. They are not records of paid success. Enable the model and its matching price before submitting. The examples deliberately set `speed: "fast"` for consistent cross-version use; omitting speed also uses Fast. Set `speed: "relax"` explicitly only when you want Relax and the version supports that path. ```json {"model":"midjourney-v8.2","prompt":"A red paper boat on a calm pond","speed":"fast","size":"16:9","raw":true,"hd":true} ``` ```json {"model":"midjourney-v8.1","prompt":"A red paper boat on a calm pond","speed":"fast","size":"4:3","raw":true,"stylize":100} ``` ```json {"model":"midjourney-v7","prompt":"A red paper boat on a calm pond","speed":"fast","quality":2,"size":"16:9","raw":true} ``` ```json {"model":"midjourney-v6.1","prompt":"A red paper boat on a calm pond","speed":"fast","quality":1,"stylize":100,"stop":100} ``` ```json {"model":"midjourney-v6","prompt":"A red paper boat on a calm pond","speed":"fast","quality":1,"size":"4:3","raw":true} ``` ```json {"model":"midjourney-v5.2","prompt":"A red paper boat on a calm pond","speed":"fast","quality":0.5,"stylize":100,"stop":100} ``` ```json {"model":"midjourney-v5.1","prompt":"A red paper boat on a calm pond","speed":"fast","quality":1,"size":"1:1","raw":true} ``` ```json {"model":"niji-v7","prompt":"An illustrated red paper boat on a calm pond","speed":"fast","size":"16:9","raw":true} ``` ```json {"model":"niji-v6","prompt":"An illustrated red paper boat on a calm pond","speed":"fast","quality":1,"stylize":100,"raw":true} ``` ## More language examples These examples show the request format for an enabled deployment. Keep API keys in server-side code. ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "midjourney-v8.2", "prompt": "A red paper boat on a calm pond at sunrise, soft mist, no lettering", "speed": "fast", "size": "16:9", "raw": true }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "midjourney-v8.2", "prompt": "A red paper boat on a calm pond at sunrise, soft mist, no lettering", "speed": "fast", "size": "16:9", "raw": True, }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'midjourney-v8.2', prompt: 'A red paper boat on a calm pond at sunrise, soft mist, no lettering', speed: 'fast', size: '16:9', raw: true, }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model":"midjourney-v8.2", "prompt":"A red paper boat on a calm pond at sunrise, soft mist, no lettering", "speed":"fast","size":"16:9","raw":true }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") res, err := (&http.Client{Timeout:60*time.Second}).Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint and task result Use `POST https://api.toklab.ai/v1/images/generations` with `Authorization: Bearer YOUR_API_KEY` and `Content-Type: application/json`. All image operations use this endpoint. The response contains an `id`, `model`, `status: "processing"`, and `created_at`. Keep that ID and poll: ```bash curl "https://api.toklab.ai/v1/tasks/$TASK_ID" \ -H "Authorization: Bearer $TOKLAB_API_KEY" ``` A task has `processing`, `completed`, or `failed` status. Completed images are in `output.data`, as objects containing `url` and an optional one-based `index`. `output.action` identifies the operation; `output.seed` may be present. Describe results use `output.text`, an array of descriptions. An editing step may finish with `output.awaiting_input: true` and no images; submit a subsequent `modal` action using that task as its parent. Grid selection (`upscale` with `mode: "select"`) has zero image-job usage because it retrieves an existing choice. Opening the input-only inpaint step also has zero usage; the final successful modal generation is charged once. A configured model price is still required. Image URLs point to delivered results. No monetary fields are returned. When `output.grid` is `true`, one delivered file contains a grid of image choices; it is not expanded into individual image URLs. Parent actions can address the grid’s image positions even when `output.data` has one URL. Neither a fixed number of descriptions nor English output is guaranteed. Display the returned text as supplied. Do not assume every task has four images: ordinary generation usually yields four; a V8 draft set can contain 24; an upscale yields one; describe or an editing-input step can have no images. Read the returned array. ## Generation parameters Known fields do not accept `null`. Unknown JSON fields are discarded; unknown native flags are errors. This API uses URL references, public task IDs and polling, with no arbitrary image count or automatic batch expansion. Read the version and combination rules above in addition to this union table. | Field | Type | Default | Constraints | | ----------------- | ------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | One of the nine explicit IDs. | | `action` | string | `imagine` | See actions below. | | `prompt` | string | none | Imagine requires a text description, also with image prompts. Some compatible requests have an 8,192-character limit after flags and image URLs are compiled. | | `image_urls` | URL array | none | Public HTTP(S) images; leading prompt URLs precede this array. Order and repeated URLs are preserved. | | `speed` | string | `fast` | Relax, Fast or Turbo. Complete version/parameter/action combinations apply. No automatic speed change. | | `size` | string | omitted | Positive finite `W:H`, not pixel dimensions. Integer ratios up to 14:1 have wider compatibility; V8 HD's narrower integer-ratio path allows up to 4:1. | | `quality` | number or numeric string | omitted | 0.25, 0.5, 1 or 2 across all versions; 4 additionally for V7/V6.1/V6/Niji 6 on compatible requests. | | `seed` | number | omitted | Finite and within ±9,007,199,254,740,991; integer and range restrictions depend on the complete request, as described above. | | `stylize` | number | omitted | 0–1,000; fractional values have narrower availability. | | `chaos` | number | omitted | 0–100; fractional values have narrower availability. | | `weird` | number | omitted | 0–3,000; fractional values have narrower availability. | | `raw` | boolean | omitted | `style: "raw"` is an alias. An explicit structured `raw: false` overrides it. | | `style` | string | omitted | Other nonempty style strings use documented compatible paths; no guarantee of visual effect on every version. | | `tile` | boolean | omitted | Repeatable tile input. | | `negative_prompt` | string | none | Exclusions; no embedded flags or permutations. Niji 6 has narrower combinations. | | `iw` | number | omitted | 0–3 for every version. No image or guessed default is inserted. | | `cref` | URL | none | One character-reference URL; documented general input, version effects await verification. | | `cw` | number | omitted | 0–100; integer values have wider availability. No hard dependency is inferred beyond documented request behavior. | | `sref` | string | none | Exactly one plain HTTP(S) URL is currently executable. | | `sw` | number | omitted | Integer 0–1,000 has wider availability; other finite values need a compatible request. | | `dref` | URL | none | One depth-reference URL, except V6. Version effects remain unverified. | | `dw` | number | omitted | 0–100, except V6. No undocumented default or mandatory `dref` dependency is inserted. | | `oref` | URL | none | Midjourney V7 Omni Reference. Combined Draft billing remains unresolved. | | `ow` | number | omitted | Finite Omni weight. Requires `oref` to determine correct reference billing. | | `draft` | boolean | omitted | Midjourney V7 or V8, with output-count and speed restrictions above. Niji Draft is unavailable. | | `hd` | boolean | omitted | V8 high definition. On supported earlier versions it is a documented standard-output no-op with no HD charge. | | `stop` | number | omitted | 10–100. Not available for Niji 7; other version/extra-check/integer combinations apply. | | `profile` | string | none | Explicit nonempty profile code on compatible non-Relax requests; no default profile is assumed. | | `nsfw_check` | boolean | omitted | Additional content check where available. Normal safety checks cannot be disabled. | | `version` | string | from model | Optional consistency check; must match the model ID. | | `niji` | boolean | from model | Optional consistency check; must match the model family. | | `extra` | string | none | Native parameters only, no prose. | | `metadata` | object | none | Client metadata retained with the task; not an image-generation parameter. | ### Recognized syntax with no current execution path These fields remain visible so their status is explicit. They return an unavailable-combination error instead of being dropped, approximated or treated as already verified capabilities. | Field or form | Current status | | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `sv` | Finite numeric input recognized; no established execution contract. No model-vendor range is imposed as an API fact. | | Multiple/weighted `sref`, numeric style codes or `random` | Recognized syntax; the executable API contract currently requires one plain URL. | | Bare `--p` / empty `profile` | A specific profile code is required; an account's default is not substituted. | | `exp` | Finite numeric input recognized; execution semantics remain unverified. | | `edit` | HTTP(S) reference URL tokens recognized; no established execution mapping. Distinct from ordinary image prompts and the modal action. | | `sd: true` | Explicit standard-definition selection has no verified equivalent. Omit it for standard generation. `sd: false` has narrower compatible availability. | | `repeat` | Integer 2–40 recognized; multiple jobs require a separate billing/delivery contract. Prompt permutations are also unavailable. | | HD + Turbo; Omni Reference + Draft | No approved combination price. A supported individual field does not make an unpriced combination submit-ready. | ## Native parameter translation The order of precedence is **structured field → `extra` → prompt suffix**. This example uses a final aspect ratio of `16:9` and stylization of `80`: ```json { "model": "midjourney-v8.2", "prompt": "A paper boat --ar 1:1 --s 50", "extra": "--ar 4:3 --s 80", "size": "16:9", "speed": "fast" } ``` Aliases include `--ar`/`--aspect` → `size`, `--s` → `stylize`, `--c` → `chaos`, `--w` → `weird`, `--q` → `quality`, `--no` → `negative_prompt`, and `--p` → `profile`. `--v` and `--niji` must agree with the model ID. `--fast`, `--relax` and `--turbo` are speed switches. `--raw`, `--tile`, `--draft`, `--hd` and `--sd` take no value. Conflicting aliases in a single source, such as `--s 50 --stylize 80`, are rejected. Boolean JSON `false` omits that switch; it does not become a literal native `false` argument. Ordinary quoted prose and URL query strings are preserved. Known control flags inside quotes, such as `"--hd"`, `"--q 2"` or `"--turbo"`, are rejected rather than allowed to bypass version, task-count or pricing checks. Structured string parameters also reject quoted embedded flags. Structured reference and negative-prompt fields cannot contain embedded `--parameters`. Ordinary `::` prompt text is preserved. Compatibility still depends on the complete request; the API never rewrites a multiprompt into a different prompt. ## Image actions and parent tasks Use your returned TokLab `parent_task_id`, the same model, and an image `index` where required. Indices start at 1. Do not supply external task IDs, `task_id`, or private button IDs. A parent must belong to your account, remain usable, and have the required completed result. Its original generation context is preserved; expiration is checked before a child task starts. **A follow-up stays attached to its original task.** If that task's original execution context is unavailable, expired or changed, the action is rejected or fails; the system does not transfer the task ID or recreate its parent elsewhere. This applies to variation, upscale, reroll, remix, zoom, pan, inpaint and modal continuations. Keep using each returned public task ID for the next supported step. ### Action availability by version `Parent` means an implemented path exists **only if your completed parent exposes the corresponding action**; it is not a guarantee that any image can use it. `Conditional` adds the restrictions below. No cell claims a paid action has passed live acceptance. All actions still require a configured price and the requested speed. | Model | Variation | Grid select | Real upscale | Remix | Reroll / Zoom | Pan | Inpaint → Modal | Describe | | ----------------- | --------- | ----------- | --------------- | ----------- | ------------- | ----------- | --------------- | ----------- | | `midjourney-v8.2` | Parent | Parent | Unverified | Parent | Conditional | Conditional | Unavailable | Fast only | | `midjourney-v8.1` | Parent | Parent | Unverified | Parent | Conditional | Conditional | Unavailable | Fast only | | `midjourney-v7` | Parent | Parent | Parent | Unavailable | Parent | Parent | Parent | Fast only | | `midjourney-v6.1` | Parent | Parent | Parent | Unavailable | Parent | Parent | Parent | Fast only | | `midjourney-v6` | Parent | Unavailable | Parent | Unavailable | Parent | Conditional | Unavailable | Fast only | | `midjourney-v5.2` | Parent | Parent | Parent: 2x / 4x | Unavailable | Parent | Parent | Parent | Unavailable | | `midjourney-v5.1` | Parent | Parent | Parent: 2x / 4x | Unavailable | Parent | Parent | Parent | Unavailable | | `niji-v7` | Parent | Parent | Unverified | Unavailable | Parent | Parent | Parent | Unavailable | | `niji-v6` | Parent | Parent | Parent | Unavailable | Parent | Parent | Parent | Fast only | * **Remix:** V8 has a compatible parent-dependent operation. Other versions remain unavailable because the required parent execution mode and follow-up price have not both been established. A returned action hint alone does not establish a priced operation. * **Pan:** V8 and V6 currently require Fast, explicit `scale` 1.1–3, and no extra `nsfw_check: true`. Other models may either accept the parent path's built-in scale or require explicit scale. A replacement prompt is supported only on the explicit-scale path. * **Prompt and ordinary parameter edits:** compatible Fast parent contexts accept replacement text and ordinary generation parameters for `variation`, `pan`, and `zoom`. The same model version is retained. Other parent contexts accept only inherited settings. HD, Draft or Omni Reference overrides that change the billing mode remain unpriced and blocked; earlier-version HD no-ops do not add an HD charge. Parent identity and inherited parameters are checked by the owner-scoped quote. A Turbo parent is never silently billed as a Fast follow-up. * **Real upscale:** V5 uses `2x`/`4x`; other versions use `subtle`/`creative`. `select` only retrieves a grid choice and has zero image-job usage. An available Select operation does not establish a real upscale operation. V8 and Niji 7 real upscale command semantics remain unverified; their Select availability does not change that status. * **Inpaint → Modal:** start `inpaint` with the parent and no mask, replacement prompt or generation-parameter overrides. When it returns `awaiting_input: true`, use its returned public task ID for `modal`, optionally adding `prompt` and `mask_url`. The input stage has zero jobs; a successful final modal generation is one charged job. A final modal with a mask is priced as inpainting, while a final modal without a mask is priced as outpainting. These price categories are derived from `mask_url`, not extra values you can pass in `mode`. V8 and V6 do not currently have this sequence. * **Describe:** needs exactly one independent image URL and returns text. Available with Fast speed for V8.2, V8.1, V7, V6.1, V6 and Niji 6. Omit `nsfw_check` or use `false`; `true`, Relax and Turbo are unavailable. Describe requires API or administrator access because the signed-in form retains its additional content check. The selected model ID does not make Describe a generation in that image-model version. Incompatible combinations are rejected before submission; inputs are never silently changed. * **Blend:** unavailable for every version because the current execution contract cannot preserve the selected version. Use `imagine` with a text description and image prompt URLs when that is the operation you intend; Blend is not automatically rewritten. | Action | Inputs and constraints | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `imagine` | No parent. Text, image prompts and generation parameters. | | `variation` | Parent and index. `mode: "subtle"` (default) or `"strong"`. Replacement text and ordinary generation parameters are accepted only where the parent supports them. | | `upscale` | Parent and index. `mode: "select"` (default) extracts an existing grid image with zero image-job usage; `subtle`/`creative` perform a real upscale. V5 real upscale modes are `2x`/`4x`. Availability depends on the parent's available actions. No prompt or generation parameters. | | `remix-strong`, `remix-subtle` | Parent and index, optional replacement prompt; `remix` aliases `remix-strong`. If `mode` is supplied it must match the action. Generation-parameter edits are currently unavailable for Remix. | | `reroll` | Parent; inherits prompt. No generation parameters. | | `zoom` | Parent and index. `zoom_ratio` 1.1–2, default 2; the value is preserved. Some parents accept only exact 1.5 or 2, while compatible parents accept continuous values. The API never rounds the request to fit another operation. Replacement text and ordinary generation parameters are accepted only for a compatible parent; no rounding or speed downgrade. | | `pan` | Parent, index and `direction` (`left`, `right`, `up`, `down`). Optional `scale` 1.1–3 is required by some supported contexts. Replacement text and ordinary generation parameters are context-dependent. | | `describe` | Exactly one `image_urls` URL; Fast only for the six models above. No parent, prompt or generation parameters; `nsfw_check` must be omitted or false. Returns text. | | `blend` | Recognized but unavailable pending version-preserving execution. 2–5 images, no text; only `size` as a generation parameter. | | `inpaint` | Parent; starts an editing-input step where available. Editing masks are not converted between incompatible coordinate systems. | | `modal` | Parent awaiting input; optional replacement prompt and HTTP(S) PNG `mask_url` where supported. Transparent areas are redrawn; white areas are preserved. No generation-parameter edits. | `index` ranges from 1 to the parent's available image choices, with a maximum of 24 for V8 draft and 4 for other versions. Some actions only support indices 1–4. Child actions do not accept `image_urls`; only imagine, blend and describe accept independent images. `direction`, `scale`, `zoom_ratio` and `mask_url` belong only to the actions described above. ```json { "model": "midjourney-v8.2", "action": "variation", "parent_task_id": "task_YOUR_COMPLETED_TASK", "index": 1, "mode": "subtle", "speed": "fast" } ``` ## Reference images and editing masks Use publicly accessible HTTP(S) URLs that return the image itself. For broad request compatibility, use PNG, JPEG or WebP files no larger than **12 MiB (12,582,912 bytes) each**. These are documented image formats, not an exclusive format list. The 12 MiB limit applies to some supported requests, including their image prompts, reference images and editing masks; it is not a universal limit for every available model and request combination. Keeping each file within it avoids that size restriction when changing parameters. For a supported `modal` request, `mask_url` must return a **PNG mask**: transparent areas are redrawn and white areas are preserved. Use the same dimensions as the parent image to avoid unintended alignment; this is preparation guidance, not an enforced universal dimension constraint. Start `inpaint` without a mask, then pass the mask in the subsequent `modal` request. The API does not convert between different mask conventions. Submission checks reject a confirmed oversized file where the limit applies, a confirmed non-image response, or a confirmed non-PNG modal mask. A URL, filename suffix or successful quote alone does not prove that the remote image is readable or that its pixels form the intended mask. Files are not silently converted; inspect the image and mask before submitting. Other image formats and individual parameter effects remain subject to the supported request's behavior. ## Errors and verification status Invalid fields, version mismatches and unavailable combinations return an error before acceptance. A task accepted successfully can later fail; read its final status and error instead of resubmitting automatically. See the [error reference](https://toklab.ai/docs/api/errors) for the public error format. Failed requests are not charged. The October 18 paid checks established the output counts and completed workflows summarized at the top of this page. A completed operation does not guarantee that its images satisfy the prompt: the illustrated V6.1 masked edit returned images but did not show the requested clothing change. Other version/action combinations, individual reference effects and expiration boundaries still require separate verification. A local serializer or mocked test does not establish those results. ## Contract scope This reference defines TokLab's supported JSON and task contract, including the version-specific limits and request combinations listed above. The available API operations are assessed independently of the Midjourney website and Discord interface; a website feature does not establish API availability, and a website-only restriction is not automatically an API restriction. TokLab is not a Midjourney-operated API. Documented request support does not establish the visual effect of every parameter on every version; the remaining live checks are identified above. --- Source: https://toklab.ai/docs/minimax-h3 ## Standard and Pro Both channels support `content_filter`. It defaults to true and checks content before generation; API callers can set it to false. Upstream content restrictions may still apply. `minimax-h3` is **Pro** and keeps its existing request format and behavior. The native-format sections below describe Pro. **Standard** uses `minimax-h3-standard` with its own flat JSON body at the same `/v1/videos/generations` endpoint. It is not a Max or Turbo version. The two variants do not automatically fall back to one another. ```json { "model": "minimax-h3-standard", "prompt": "A sailboat crosses a quiet bay, with soft wind and waves.", "quality": "high", "content_filter": true, "duration_s": 5, "resolution": "768p", "aspect_ratio": "16:9" } ``` Standard accepts these fields only. URLs must be public HTTP(S), without credentials; file uploads and base64 are not accepted. | Field | Type | Required / default | Values | | ----------------------- | --------- | ------------------ | ------------------------------------------------------------- | | `model` | string | required | `minimax-h3-standard` | | `prompt` | string | required | non-empty; required in every mode | | `quality` | string | required | `low`, `high`; same price | | `duration_s` | number | 5 | 5–15, including decimals | | `resolution` | string | `768p` | `480p`, `768p`, `1080p`, `2k`, `4k` | | `aspect_ratio` | string | `16:9` | `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, `21:9` | | `seed` | integer | random | 0–9223372036854775807 | | `watermark` | boolean | false | true / false | | `enhance` | boolean | true | prompt rewriting; false preserves the prompt | | `priority` | integer | 1000 | 1000 / 0 | | `content_filter` | boolean | true | TokLab content check before generation; false skips the check | | `first_frame_image_url` | string | optional | one image URL | | `last_frame_image_url` | string | optional | requires first frame | | `reference_image_url` | string\[] | optional | 1–4 image URLs | | `reference_video_url` | string\[] | optional | one video URL | First/last frames cannot be combined with references. No media means text-to-video. Reference images and a reference video can be combined. Independent reference audio is not supported. Every output includes native audio. Low favors speed; High favors fidelity, with no claim that either matches Pro's quality. Images: up to 30 MiB each; JPEG, PNG, WebP, GIF, BMP, TIFF, HEIC, HEIF or AVIF. There is no image dimension limit; large images may be resized before generation. Videos: up to 100 MiB, 0.5–600 seconds, readable video stream (including MP4, MOV and WebM), even width and height of at least 64 pixels. Standard bills **ceil(duration\_s) × the live rate for the resolution**. Reference media, audio, quality and prompt rewriting add no fee. Failed tasks are not charged. Prices come from the [live pricing page](https://toklab.ai/pricing). Creation and polling use the shared asynchronous protocol below. Successful output contains `video_url`, `resolution`, `ratio` and `duration`; `duration` reflects the requested duration. Fees, supplier identifiers and supplier URLs are not returned. An unknown submission outcome must not be retried automatically. For seeds above JavaScript's safe-integer limit, serialize the integer losslessly; do not round it through `Number`. ## Pro reference MiniMax H3 (Hailuo 03) is MiniMax's multimodal video model. One request makes the picture and the sound together: a 4–15 second clip at 768P or 2K with its own dialogue, ambience and effects. The request body is MiniMax's official format with the model ID `minimax-h3`. Send it, keep the returned task ID, and read the finished video from the task. Frames and references go in as URLs. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ------------ | -------------------------------------------------------------- | ----------- | ------------ | | `minimax-h3` | text, first and last frame, reference images, videos and audio | 768P, 2K | 4–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax-h3", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "minimax-h3", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'minimax-h3', content: [ { type: 'text', text: 'A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos.' }, ], resolution: '768P', duration: 5, ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "minimax-h3", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | ---------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `minimax-h3` | | `content` | array | required | The prompt and any media, as items described below. Exactly one non-empty `text` item. | | `resolution` | enum | required | `768P` or `2K`. | | `duration` | integer | required | Any integer from 4 to 15 seconds. | | `ratio` | enum | by input | `adaptive`, `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`. Required for text alone, where `adaptive` is not accepted. | | `content_filter` | boolean | `true` | TokLab's content filter, described below. Not sent to the model. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. `extra` belongs to MiniMax-H3-Max and is not accepted for this model. ## Content items | `type` | Item | `role` | | ----------- | --------------------------------------------------------------------------------------- | ------------------------------------------------ | | `text` | `{"type": "text", "text": "..."}`, up to 7,000 characters | none | | `image_url` | `{"type": "image_url", "image_url": {"url": "https://..."}, "role": "..."}` | `first_frame`, `last_frame` or `reference_image` | | `video_url` | `{"type": "video_url", "video_url": {"url": "https://..."}, "role": "reference_video"}` | `reference_video` | | `audio_url` | `{"type": "audio_url", "audio_url": {"url": "https://..."}, "role": "reference_audio"}` | `reference_audio` | A single image without a `role` is the first frame. With more than one image, every image needs a `role`. ## Modes The items in `content` decide the mode; there is no mode field. | Mode | `content` holds | `ratio` | | ------------------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | Text to video | one `text` item | required, not `adaptive` | | Image to video | `text` plus a `first_frame` and/or a `last_frame` image | any value is treated as `adaptive`: the image sets the shape | | Reference to video | `text` plus any mix of up to 9 `reference_image`, 3 `reference_video` and 3 `reference_audio` items | optional, default `adaptive` | Frames and references cannot be combined in one request. ```json { "model": "minimax-h3", "content": [ {"type": "text", "text": "The person in the photo speaks to camera: Follow the wind. Voice follows the reference audio."}, {"type": "image_url", "image_url": {"url": "https://example.com/person.jpg"}, "role": "reference_image"}, {"type": "audio_url", "audio_url": {"url": "https://example.com/voice.mp3"}, "role": "reference_audio"} ], "resolution": "2K", "duration": 6 } ``` ## Media inputs Every image, video and audio item is a public HTTP(S) URL. Base64 data URIs and `mm_file://` IDs are not accepted: upload the file to your own storage and pass its URL. | Input | Format | Limits | | ----- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Image | JPG, JPEG, PNG, WebP, HEIC, HEIF | 30 MB or less; each side 256–5760 px; width / height 0.4–2.5 | | Video | MP4, MOV (H.264 or H.265) | 50 MB or less; 2–15 seconds each, 15 seconds in total; each side 256–5760 px; width / height 0.4–2.5; 23.976–60 fps | | Audio | WAV, MP3 | 15 MB or less; 2–15 seconds each, 15 seconds in total | Reference videos are measured when the request is accepted; one whose length cannot be read is refused with nothing charged. Other limits are checked before generation, and a request that breaks one fails without charge. ## Content filter `content_filter` is `true` unless you set it. With the filter on, the request, its text and its media, is moderated before generation. A flagged request fails with code `60001` and is not charged. Set `content_filter` to `false` to skip moderation. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. MiniMax H3 is billed per second of video, at a rate set by the output resolution, plus input images beyond the first five: ```text billed seconds = duration + ceil(Σ each reference video's seconds) extra images = max(0, number of images − 5) cost = billed seconds × rate per second + extra images × rate per image ``` First frames, last frames and reference images all count as images. Reference audio is not billed. Both quantities are known when the request is accepted, so the amount reserved is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "minimax-h3", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "minimax-h3", "status": "completed", "created_at": 1789689600, "finished_at": 1789689740, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4", "resolution": "768P", "ratio": "16:9", "duration": 5 } } ``` `ratio` is the aspect ratio the clip was made at, including the one chosen for `adaptive`. In our test, a 4-second 768P clip at `16:9` came back as MP4 (H.264) at 1344 × 768 and 24 fps, with a stereo AAC track at 32 kHz. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "minimax-h3", "status": "failed", "error": { "code": 60001, "message": "the request was blocked by content moderation" } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe the shot and its sound together: subject, place, camera, light, dialogue and effects. * Write dialogue into the prompt and attach a reference audio clip when the voice should follow it. * Draft at `768P`, then render the final shot at `2K` with the same request. * Use a first and a last frame to control where a shot starts and ends; use references to keep a product, a person or a motion. * Add `no text, no logos` to keep invented marks out. ## Related * [MiniMax H3 pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/minimax-h3.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/minimax-h3.md) --- Source: https://toklab.ai/docs/minimax-h3-max MiniMax H3 Max is the faster-generation variant of MiniMax H3. One request makes the picture and the sound together: a 5–15 second clip at 480P or 768P with its own dialogue, ambience and effects. The request body is MiniMax's official format with the model ID `minimax-h3-max`. Send it, keep the returned task ID, and read the finished video from the task. Frames and references go in as URLs. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ---------------- | -------------------------------------------------------------- | ----------- | ------------ | | `minimax-h3-max` | text, first and last frame, reference images, videos and audio | 480P, 768P | 5–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax-h3-max", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "minimax-h3-max", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'minimax-h3-max', content: [ { type: 'text', text: 'A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos.' }, ], resolution: '768P', duration: 5, ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "minimax-h3-max", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | ----------------------------- | ------- | ---------- | ------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `minimax-h3-max` | | `content` | array | required | The prompt and any media, as items described below. Exactly one non-empty `text` item. | | `resolution` | enum | required | `480P` or `768P`. | | `duration` | integer | required | Any integer from 5 to 15 seconds. | | `ratio` | enum | by input | `adaptive`, `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`. Required for text alone, where `adaptive` is not accepted. | | `extra` | object | omitted | Optional prompt expansion settings. | | `extra.prompt_expansion_mode` | enum | `balanced` | `disabled`, `balanced`, or `quality`. Omitting the object or property preserves the model default. | | `content_filter` | boolean | `true` | TokLab's content filter, described below. Not sent to the model. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. `extra` is an optional strict object containing only `prompt_expansion_mode`. All fields reject `null`; omit optional fields instead. ## Content items | `type` | Item | `role` | | ----------- | --------------------------------------------------------------------------------------- | ------------------------------------------------ | | `text` | `{"type": "text", "text": "..."}`, up to 7,000 characters | none | | `image_url` | `{"type": "image_url", "image_url": {"url": "https://..."}, "role": "..."}` | `first_frame`, `last_frame` or `reference_image` | | `video_url` | `{"type": "video_url", "video_url": {"url": "https://..."}, "role": "reference_video"}` | `reference_video` | | `audio_url` | `{"type": "audio_url", "audio_url": {"url": "https://..."}, "role": "reference_audio"}` | `reference_audio` | A single image without a `role` is the first frame. With more than one image, every image needs a `role`. ## Modes The items in `content` decide the mode; there is no mode field. | Mode | `content` holds | `ratio` | | ------------------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | Text to video | one `text` item | required, not `adaptive` | | Image to video | `text` plus a `first_frame` and/or a `last_frame` image | any value is treated as `adaptive`: the image sets the shape | | Reference to video | `text` plus any mix of up to 9 `reference_image`, 3 `reference_video` and 3 `reference_audio` items | optional, default `adaptive` | Frames and references cannot be combined in one request. The official documentation lists last-frame-only input, but also contains a conflicting requirement to pair it with a first frame. That case has not been verified on TokLab. Use both frames when an ending image is required. ```json { "model": "minimax-h3-max", "content": [ {"type": "text", "text": "The person in the photo speaks to camera: Follow the wind. Voice follows the reference audio."}, {"type": "image_url", "image_url": {"url": "https://example.com/person.jpg"}, "role": "reference_image"}, {"type": "audio_url", "audio_url": {"url": "https://example.com/voice.mp3"}, "role": "reference_audio"} ], "resolution": "768P", "duration": 6 } ``` ## Media inputs Every image, video and audio item is a public HTTP(S) URL. Base64 data URIs and `mm_file://` IDs are not accepted: upload the file to your own storage and pass its URL. | Input | Format | Limits | | ----- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Image | JPG, JPEG, PNG, WebP, HEIC, HEIF | 30 MB or less; each side 256–5760 px; width / height 0.4–2.5 | | Video | MP4, MOV (H.264 or H.265) | 50 MB or less; 2–15 seconds each, 15 seconds in total; each side 256–5760 px; width / height 0.4–2.5; 23.976–60 fps | | Audio | WAV, MP3 | 15 MB or less; 2–15 seconds each, 15 seconds in total | Reference videos are measured when the request is accepted; one whose length cannot be read is refused with nothing charged. Other limits are checked before generation, and a request that breaks one fails without charge. ## Content filter `content_filter` is `true` unless you set it. With the filter on, the request, its text and its media, is moderated before generation. A flagged request fails with code `60001` and is not charged. Set `content_filter` to `false` to skip moderation. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. MiniMax H3 Max prices generated output seconds and reference-video seconds separately, by the output resolution. The first two images are free; every later image adds a charge. ```text output seconds = reported generated seconds input seconds = reported reference-video seconds extra images = max(0, reported input image count − 2) cost = output seconds × output rate + input seconds × reference-video rate + extra images × image rate ``` Reference-video lengths are added together and rounded to the nearest whole second for final usage. Two 2.4-second clips therefore contribute five input seconds. Reference audio has no input charge. First and last frames count as images, so two frames alone add no image charge. Final usage is priced at the rate captured for your request. If a complete usage report is unavailable, the accepted estimate is used. View charges in account usage history; public task responses do not include fees. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "minimax-h3-max", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "minimax-h3-max", "status": "completed", "created_at": 1789689600, "finished_at": 1789689740, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4", "resolution": "768P", "ratio": "16:9", "duration": 5 } } ``` `ratio` is the aspect ratio the clip was made at, including the one chosen for `adaptive`. The task contains the actual resolution, ratio and duration when reported. The JSON above illustrates the response shape; it is not a measured generation result. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "minimax-h3-max", "status": "failed", "error": { "code": 60001, "message": "the request was blocked by content moderation" } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe the shot and its sound together: subject, place, camera, light, dialogue and effects. * Write dialogue into the prompt and attach a reference audio clip when the voice should follow it. * Draft at `480P`, then select `768P` when you need more detail. A new render is a separate paid request. * Use `extra: {"prompt_expansion_mode": "disabled"}` for an already complete prompt, or choose `balanced` / `quality` expansion. * Use a first and a last frame to control where a shot starts and ends; use references to keep a product, a person or a motion. * Add `no text, no logos` to keep invented marks out. ## Related * [MiniMax H3 Max pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/minimax-h3-max.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/minimax-h3-max.md) ## Contract sources Parameters follow [MiniMax’s video-generation documentation](https://platform.minimax.io/docs/api-reference/video-generation-v2-create). TokLab uses its own model ID and asynchronous task interface, URL-only media and hosted result delivery; callbacks and cancellation are unavailable. `content_filter` is a TokLab extension. --- Source: https://toklab.ai/docs/minimax-h3-max-turbo MiniMax H3 Max Turbo generates short videos from text or frame images. Use model ID `minimax-h3-max-turbo`, keep the returned task ID, and poll for the finished video. This page describes the native content-array interface offered on TokLab. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ---------------------- | -------------------------------------- | ----------- | ------------ | | `minimax-h3-max-turbo` | text, first frame, optional last frame | 480P, 768P | 5–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax-h3-max-turbo", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "minimax-h3-max-turbo", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'minimax-h3-max-turbo', content: [ { type: 'text', text: 'A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos.' }, ], resolution: '768P', duration: 5, ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "minimax-h3-max-turbo", "content": [ {"type": "text", "text": "A small sailboat glides across a calm turquoise bay at sunrise, seagulls in the distance, the sound of water and wind. No text, no logos."} ], "resolution": "768P", "duration": 5, "ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | ----------------------------- | ------- | ---------- | ------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `minimax-h3-max-turbo` | | `content` | array | required | The prompt and any media, as items described below. Exactly one non-empty `text` item. | | `resolution` | enum | required | `480P` or `768P`. | | `duration` | integer | required | Any integer from 5 to 15 seconds. | | `ratio` | enum | by input | `adaptive`, `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`. Required for text alone, where `adaptive` is not accepted. | | `extra` | object | omitted | Optional prompt expansion settings. | | `extra.prompt_expansion_mode` | enum | `balanced` | `disabled`, `balanced`, or `quality`. Omitting the object or property preserves the model default. | | `content_filter` | boolean | `true` | TokLab's content filter, described below. Not sent to the model. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. `extra` is an optional strict object containing only `prompt_expansion_mode`. All fields reject `null`; omit optional fields instead. ## Content items | `type` | Item | `role` | | ----------- | ----------------------------------------------------------------------------- | ----------------------------- | | `text` | `{"type":"text","text":"..."}`, up to 7,000 characters | none | | `image_url` | `{"type":"image_url","image_url":{"url":"https://..."},"role":"first_frame"}` | `first_frame` or `last_frame` | Exactly one non-empty text item is required. A single image without a role is treated as the first frame. At most one first frame and one last frame are accepted; a last frame requires a first frame. Reference images, video and audio are not supported. ## Modes The items in `content` determine the mode; no `mode` field is sent. | Mode | Content | Ratio | | -------------- | ----------------------------------------------- | ----------------------------------------------------------- | | Text to video | one text item | required; one of six concrete ratios, never `adaptive` | | Image to video | text and a first frame, optionally a last frame | follows the frame images; another valid value has no effect | ```json { "model": "minimax-h3-max-turbo", "content": [ {"type":"text","text":"Slowly move closer to the ceramic bowl. Keep the glaze and window lighting consistent."}, {"type":"image_url","image_url":{"url":"https://example.com/first.jpg"},"role":"first_frame"}, {"type":"image_url","image_url":{"url":"https://example.com/last.jpg"},"role":"last_frame"} ], "resolution": "480P", "duration": 5, "ratio": "adaptive", "extra": {"prompt_expansion_mode":"balanced"} } ``` ## Frame images Use public HTTP(S) URLs without embedded credentials. Base64 and `mm_file://` IDs are not accepted. Images may be JPG, JPEG, PNG, WebP, HEIC or HEIF, no larger than 30 MB each, with each side 256–5760 pixels and width/height between 0.4 and 2.5. The input is checked before generation. Use matching compositions and aspect ratios for two frames. ## Content filter `content_filter` is `true` unless you set it. With the filter on, the request, its text and its media, is moderated before generation. A flagged request fails with code `60001` and is not charged. Set `content_filter` to `false` to skip moderation. ## Pricing dimensions The [pricing page](https://toklab.ai/pricing) shows current rates. Turbo has one charge: output seconds at the selected resolution. First and last frames and prompt expansion have no separate charge. ```text cost = reported output seconds × output-second rate for the resolution ``` The estimate uses requested whole seconds. Final billing uses the completed task's output-second usage at the rate captured for the request. If valid usage is unavailable, the accepted estimate is used. Media-container duration can differ slightly from billed seconds. View charges in your account usage history; public task responses do not include fees. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "minimax-h3-max-turbo", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "minimax-h3-max-turbo", "status": "completed", "created_at": 1789689600, "finished_at": 1789689740, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4", "resolution": "768P", "ratio": "16:9", "duration": 5 } } ``` `ratio` is the aspect ratio the clip was made at, including the one chosen for `adaptive`. The task contains the actual resolution, ratio and duration when reported. The JSON above illustrates the response shape; it is not a measured generation result. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "minimax-h3-max-turbo", "status": "failed", "error": { "code": 60001, "message": "the request was blocked by content moderation" } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe one subject, action, camera movement and lighting setup per shot. * Use 480P for a draft and 768P for more output detail. Every new generation is a separate paid request. * Supply a first frame to establish the opening composition; add a last frame only when you also supply the first. * Use `extra.prompt_expansion_mode` to choose `disabled`, `balanced` or `quality`; omission preserves `balanced`. * Review the full clip and its audio before publishing. A prompt does not guarantee precise product geometry or lettering. ## Related * [MiniMax H3 Max Turbo pricing](https://toklab.ai/pricing) * [Download OpenAPI](https://toklab.ai/docs/minimax-h3-max-turbo.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/minimax-h3-max-turbo.md) ## Contract scope This interface uses MiniMax's content-array request format with TokLab model IDs, asynchronous tasks, URL-only images and hosted result delivery. Callbacks and cancellation are unavailable. `content_filter` is a TokLab input check, not a MiniMax parameter. Seed and watermark controls are not accepted by this interface. --- Source: https://toklab.ai/docs/minimax-m3-1-flash Use the exact model ID `MiniMax-M3.1-Flash`. Live prices are on the [pricing page](https://toklab.ai/pricing). The [OpenAPI specification](https://toklab.ai/docs/minimax-m3-1-flash.openapi.json) defines nested request and response fields. ## Quick start ```bash curl https://api.toklab.ai/v1/chat/completions \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model":"MiniMax-M3.1-Flash", "messages":[{"role":"user","content":"What is 17 multiplied by 23?"}], "max_completion_tokens":2048, "reasoning_effort":"low" }' ``` ```python import json import os import urllib.request request = urllib.request.Request( "https://api.toklab.ai/v1/chat/completions", headers={ "Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}", "Content-Type": "application/json", }, data=json.dumps({ "model": "MiniMax-M3.1-Flash", "messages": [{"role": "user", "content": "What is 17 multiplied by 23?"}], "max_completion_tokens": 2048, "reasoning_effort": "low", }).encode(), method="POST", ) with urllib.request.urlopen(request, timeout=120) as response: result = json.load(response) print(result["choices"][0]["message"]["content"]) ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/chat/completions', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'MiniMax-M3.1-Flash', messages: [{ role: 'user', content: 'What is 17 multiplied by 23?' }], max_completion_tokens: 2048, reasoning_effort: 'low', }), signal: AbortSignal.timeout(120000), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const result = await response.json(); console.log(result.choices[0].message.content); ``` ```go package main import ( "fmt" "io" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "MiniMax-M3.1-Flash", "messages": [{"role": "user", "content": "What is 17 multiplied by 23?"}], "max_completion_tokens": 2048, "reasoning_effort": "low" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/chat/completions", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 120 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } data, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(data)) } ``` This example chooses an output limit; it is not the model's default. Keep keys on your server. ## Formats and authentication | Format | Endpoint | Required fields | Total top-level fields | | ---------------- | --------------------------- | ------------------- | ---------------------- | | Chat Completions | `POST /v1/chat/completions` | `model`, `messages` | 13 | | Messages | `POST /v1/messages` | `model`, `messages` | 12 | | Responses | `POST /v1/responses` | `model`, `input` | 13 | Send `Content-Type: application/json` and `Authorization: Bearer $TOKLAB_API_KEY`. Messages also accepts `x-api-key`; SDK clients may include `anthropic-version: 2023-06-01`. These formats keep their native bodies and response structures. ## Parameters All fields except the required ones above are optional. Omission differs from explicit `null`: a field accepts null only where the OpenAPI declares it. Unsupported top-level fields are discarded; invalid values of supported fields return an error. ### Chat Completions | Field | Type | Rule | | ----------------------- | ------- | ------------------------------------------------------------------------------------------ | | `model` | string | Exactly `MiniMax-M3.1-Flash` | | `messages` | array | Native conversation messages; preserve reasoning and tool history | | `thinking` | object | `type` can only be `adaptive` | | `reasoning_effort` | string | `low`, `medium`, `high`, `xhigh`, `max`; default `max` | | `reasoning_split` | boolean | Only `true` | | `stream` | boolean | Default `false` | | `stream_options` | object | `include_usage` controls streaming usage visibility | | `max_completion_tokens` | integer | 1–524288; includes reasoning and answer tokens | | `max_tokens` | integer | Legacy output limit, 1–524288; prefer `max_completion_tokens` | | `temperature` | number | Accepted but ignored; model uses 1 | | `top_p` | number | Greater than 0 and at most 1; ignored, model uses 0.95 | | `tools` | array | Function definitions: `type`, `function.name`, `function.parameters`, optional description | | `n` | integer | Only 1 | ### Messages | Field | Type | Rule | | --------------- | --------------- | ----------------------------------------------------------------- | | `model` | string | Exactly `MiniMax-M3.1-Flash` | | `messages` | array | Native user/assistant messages and content blocks | | `system` | string or array | System instructions or text blocks | | `stream` | boolean | Default `false` | | `max_tokens` | integer | 1–524288, including reasoning; optional in the model's API schema | | `temperature` | number | Accepted but ignored; model uses 1 | | `top_p` | number | Greater than 0 and at most 1; model uses 0.95 | | `tools` | array | Native function definitions with `input_schema` | | `tool_choice` | object | Only `{"type":"auto"}` | | `thinking` | object | Only `{"type":"adaptive"}` | | `output_config` | object | `effort`: `low`, `medium`, `high`, `xhigh`, `max`; default `max` | | `metadata` | object | Optional native metadata | ### Responses | Field | Type | Rule | | ------------------- | --------------- | -------------------------------------------------------------------------- | | `model` | string | Exactly `MiniMax-M3.1-Flash` | | `input` | string or array | Text or native message, function-call, function-result and reasoning items | | `instructions` | string | System instructions | | `max_output_tokens` | integer | 1–524288, including reasoning | | `temperature` | number | Accepted but ignored; model uses 1 | | `top_p` | number | Greater than 0 and at most 1; model uses 0.95 | | `stream` | boolean | Default `false` | | `tools` | array | Native function definitions | | `tool_choice` | string | Only `auto` | | `metadata` | object | Values must be strings | | `prompt_cache_key` | string | Optional cache grouping key | | `text` | object | Only `{"format":{"type":"text"}}` | | `reasoning` | object | `effort`: the five levels above; default `max` | Nested objects and full conversation histories use JSON fields. Invalid supported values block submission in the browser. ## Reasoning and limits The documented context window is 1,000,000 tokens. The output limit is 524,288 tokens, including reasoning. MiniMax recommends 131,072 output tokens for demanding tasks, but does not specify that value as a default. Thinking is always enabled. `disabled`, `none` and `minimal` are not supported thinking settings for this model. A short output budget can be exhausted before answer text appears. `service_tier`, audio input and structured JSON output are not supported features of this contract. The total request body must not exceed 64 MB. The model service validates exact context usage and remote media contents. ## Images and video | Input | Supported formats | Limit | | ------------------- | -------------------- | --------------- | | Image | JPEG, PNG, GIF, WebP | 10 MB per image | | URL or inline video | MP4, AVI, MOV, MKV | 50 MB per video | | Entire request | JSON body | 64 MB | Chat uses `image_url: {"url":"..."}` and `video_url: {"url":"..."}` content blocks. Messages uses image/video blocks with a `source` object: `{"type":"url","url":"..."}` or `{"type":"base64","media_type":"...","data":"..."}`. Responses uses `input_image` or `input_video`, whose URL value can be a string or a supported options object. `detail` accepts `low`, `default`, `high`, with `default` as the default. Video `fps` ranges from 0.2 to 5, default 1. The optional `max_long_side_pixel` is a positive integer where offered in the nested schema. ```json { "model": "MiniMax-M3.1-Flash", "messages": [{ "role": "user", "content": [ {"type": "text", "text": "Describe the main change in this clip."}, {"type": "video_url", "video_url": { "url": "https://example.com/clip.mp4", "fps": 1, "detail": "default" }} ] }], "max_completion_tokens": 2048 } ``` Replace the example URL with your own accessible file. Inline inputs use the appropriate base64 MIME type; MOV uses `video/mov`. Existing `mm_file://` video references are passed through, but this service does not provide a Files upload API. A reference still needs to be accessible to the account processing the request. ## Tools and conversation history Function tools describe actions your application can perform. A tool call is not proof that an external action has run: inspect the name and arguments, execute the action in your application, then return its result with the matching call ID. Chat continuation retains the complete assistant message, including `reasoning_content` and `tool_calls`; tool messages require `tool_call_id`. Messages continuation preserves thinking blocks, signatures, `tool_use` and `tool_result` blocks. Responses continuation appends all returned output items before the next user input. Do not flatten these histories into answer text. Arbitrary function parameter schemas and echoed reasoning fields are preserved. Chat's official reference does not define a `tool_choice` parameter for this model. ## Streaming and response fields Set `stream: true` for server-sent events. Chat emits `choices[].delta` and finishes with `[DONE]`; request `stream_options: {"include_usage":true}` to receive usage. Messages emits named events such as `message_start`, content-block updates and `message_stop`. Responses emits events such as `response.output_text.delta` and `response.completed`. Non-streaming Chat returns `choices[].message`, `finish_reason` and `usage`. Messages returns content blocks, `stop_reason` and usage. Responses returns `output` items, status and usage. Preserve the complete response when your application needs more than the displayed answer. ## Usage and current pricing The [live pricing table](https://toklab.ai/pricing) shows both input bands. Total input up to 512,000 tokens uses the first band; above 512,000 uses the second. The selected band prices the whole request, including output and cache. | Format | Full input | Output | | --------- | ------------------------------------------------------------------------------- | -------------------------------------- | | Chat | `prompt_tokens` includes cached input | `completion_tokens` includes reasoning | | Messages | Add `input_tokens`, `cache_read_input_tokens` and `cache_creation_input_tokens` | `output_tokens` includes reasoning | | Responses | `input_tokens` includes cached input | `output_tokens` includes reasoning | Cache-read and cache-write tokens are not charged a second time as ordinary input. Automatic caching checks eligible repeated prefixes of at least 512 tokens; hits are not guaranteed. No explicit cache marker is needed. Responses expose token counts, not monetary costs. Account usage records show final charges. Failed requests are not charged. ## Errors For errors, check the invalid field and the [public error reference](https://toklab.ai/docs/api/errors). The same model ID supports the three text endpoints above; it is not an embeddings or Gemini endpoint. ## Official references * [MiniMax model invocation](https://platform.minimax.io/docs/guides/text-generation) * [Chat Completions reference](https://platform.minimax.io/docs/api-reference/text-chat-openai) * [Messages reference](https://platform.minimax.io/docs/api-reference/text-chat-anthropic) * [Responses reference](https://platform.minimax.io/docs/api-reference/responses-create) * [Function-call continuation](https://platform.minimax.io/docs/guides/text-m3-function-call) * [Automatic prompt caching](https://platform.minimax.io/docs/api-reference/text-prompt-caching) --- Source: https://toklab.ai/docs/muse-image Muse Image is the image model from Meta Superintelligence Labs. One request makes one image from a prompt, or from a prompt plus up to 9 reference images, in one of seven aspect ratios. Send the request, keep the returned task ID, and read the finished image from the task. Reference images go in as URLs. ## Model IDs | Model ID | Inputs | Aspect ratios | Images per request | | ------------ | ---------------- | ------------------------------------------------- | ------------------ | | `muse-image` | text, 0–9 images | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | 1 | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/images/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "muse-image", "prompt": "A red ceramic mug on a white table, soft studio light, product photography. No text, no logos.", "aspect_ratio": "1:1" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "muse-image", "prompt": "A red ceramic mug on a white table, soft studio light, product photography. No text, no logos.", "aspect_ratio": "1:1", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/images/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'muse-image', prompt: 'A red ceramic mug on a white table, soft studio light, product photography. No text, no logos.', aspect_ratio: '1:1', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "muse-image", "prompt": "A red ceramic mug on a white table, soft studio light, product photography. No text, no logos.", "aspect_ratio": "1:1" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/images/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/images/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished image. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. References go in the same request through `image_urls`; `/v1/images/edits` is not used for this model. ## Parameters | Field | Type | Default | Notes | | -------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `muse-image` | | `prompt` | string | required | Must not be empty after trimming. Required with references too. | | `image_urls` | URL list | none | 0–9 public image URLs, 11 MB in total. Without them the request is text to image. | | `aspect_ratio` | enum | auto | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2` or `2:3`. Leave it out for auto: references set the shape; text only gives `1:1`. Do not send `"auto"`. | | `size` | enum | none | Compatibility alias of `aspect_ratio`: one of the ratios above, or `auto`. Pixel sizes such as `1024x1024` are refused. When both are valid, `aspect_ratio` wins. | | `n` | integer | `1` | Only `1`. Each request returns one image. | Fields outside this list are dropped before the request is forwarded; they never cause an error and never change the output. There is no resolution, seed, negative prompt, mask or output format setting. `callback_url` is not available; poll the task instead. ## Reference images Pass up to 9 images in `image_urls` and say in `prompt` what to keep and what to change. Muse Image uses them as references for a new picture; with `aspect_ratio` left out, the result follows their shape. ```json { "model": "muse-image", "prompt": "Keep this exact jacket; show it folded in a flat lay of hiking gear on pine boards, soft morning light.", "image_urls": ["https://example.com/jacket.png"], "aspect_ratio": "9:16" } ``` ## Media inputs Each reference is a public HTTP(S) URL. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use PNG, JPEG or WebP images; the original files must total 11 MB or less across all references. A set over that limit fails after acceptance and is not charged. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. Muse Image has one price per image: ```text cost = price per image × 1 ``` Text-only and reference requests, and every aspect ratio, cost the same. The amount reserved when the task is accepted is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "muse-image", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "muse-image", "status": "completed", "created_at": 1789689600, "finished_at": 1789689680, "output": { "created": 0, "data": [ { "url": "https://cdn.example.com/media/tasks/task_example/0.webp" } ] } } ``` The image is delivered as WebP, the model's own format; there is no output format setting. The model sets the pixel size. In our tests a text-only request came back at 1600 × 1600, `16:9` at 2048 × 1152, `3:4` at 1344 × 1792 and `9:16` at 1152 × 2048, about 50–180 seconds after submission. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "muse-image", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Name the subject, setting, light and framing; Muse Image follows a specific brief closely. * With references, say exactly what must stay the same, such as the product's color or shape. * Leave `aspect_ratio` out to match a reference's shape; set it to crop for a channel. * Add `no text, no logos` to keep invented marks out. ## Related * [Muse Image pricing](https://toklab.ai/pricing) * [Muse Video API reference](https://toklab.ai/docs/muse-video) * [Download OpenAPI](https://toklab.ai/docs/muse-image.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/muse-image.md) --- Source: https://toklab.ai/docs/muse-video Muse Video is the video model from Meta Superintelligence Labs. One request makes a clip of about 10 seconds at 720p with sound, from a prompt or from a prompt plus up to 9 reference images, in one of seven aspect ratios. Send the request, keep the returned task ID, and read the finished video from the task. Reference images go in as URLs. ## Model IDs | Model ID | Inputs | Resolution | Length | | ------------ | ---------------- | ---------- | ---------------------------- | | `muse-video` | text, 0–9 images | `720p` | about 10 seconds, with sound | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "muse-video", "prompt": "Waves rolling onto a sandy beach at sunset, slow camera pan, natural ocean sound. No text.", "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "muse-video", "prompt": "Waves rolling onto a sandy beach at sunset, slow camera pan, natural ocean sound. No text.", "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'muse-video', prompt: 'Waves rolling onto a sandy beach at sunset, slow camera pan, natural ocean sound. No text.', aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "muse-video", "prompt": "Waves rolling onto a sandy beach at sunset, slow camera pan, natural ocean sound. No text.", "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | -------------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `muse-video` | | `prompt` | string | required | Must not be empty after trimming. Required with references too. | | `image_urls` | URL list | none | 0–9 public image URLs, 11 MB in total. Without them the request is text to video. | | `aspect_ratio` | enum | auto | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2` or `2:3`. Leave it out for auto: references set the shape; text only gives `16:9`. Do not send `"auto"`. | | `size` | enum | none | Compatibility alias of `aspect_ratio`: one of the ratios above, or `auto`. When both are valid, `aspect_ratio` wins. | | `duration` | integer or string | `10` | Only `10`, `"10"` or `"10s"`. The clip runs about 10 seconds. | | `resolution` | enum | `720p` | Only `720p`. | | `audio` | boolean | `true` | Only `true`; every clip has sound. `false` is refused. | | `n` | integer | `1` | Only `1`. Each request returns one clip. | Fields outside this list are dropped before the request is forwarded; they never cause an error and never change the output. There are no first or last frame, reference video, reference audio, extend, seed or negative prompt settings. `callback_url` is not available; poll the task instead. ## Reference images Pass up to 9 images in `image_urls` and describe the motion in `prompt`. Muse Video uses them as references: the clip stays close to them, but the first frame is not a pixel copy. With `aspect_ratio` left out, the clip follows their shape. ```json { "model": "muse-video", "prompt": "The fox slowly lifts its head, wind moving through its fur, the camera pushing in gently, soft forest ambience.", "image_urls": ["https://example.com/fox.png"] } ``` ## Media inputs Each reference is a public HTTP(S) URL. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use PNG, JPEG or WebP images; the original files must total 11 MB or less across all references. A set over that limit fails after acceptance and is not charged. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. Muse Video has one price per clip: ```text cost = price per clip × 1 ``` The price is not multiplied by seconds. Text-only and reference requests, and every aspect ratio, cost the same. The amount reserved when the task is accepted is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "muse-video", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "muse-video", "status": "completed", "created_at": 1789689600, "finished_at": 1789689790, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests the clips came back as 10.0-second MP4 (H.264) files with an AAC audio track: 1280 × 720 for `16:9`, 720 × 1280 for `9:16`, and 1248 × 704 for a reference with a 16:9 shape, about 100–200 seconds after submission. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "muse-video", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, action, camera move and light, and name the sounds you want; the audio is generated together with the picture. * Make a still with [Muse Image](https://toklab.ai/docs/muse-image), then pass its URL here to set it in motion. * For vertical video, send `aspect_ratio: "9:16"`, or a portrait reference. * Add `no text` to keep invented captions out. ## Related * [Muse Video pricing](https://toklab.ai/pricing) * [Muse Image API reference](https://toklab.ai/docs/muse-image) * [Download OpenAPI](https://toklab.ai/docs/muse-video.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/muse-video.md) --- Source: https://toklab.ai/docs/pixverse-v6 PixVerse V6 is PixVerse's video model. One model ID covers five modes: text to video, image to video, a transition between a first and a last frame, multi-image reference, and extending a clip you already made. The mode follows the fields you send. Clips are 1–15 seconds at 360p, 540p, 720p or 1080p, with optional native audio. Send the request, keep the returned task ID, and read the finished video from the task. Images go in as URLs. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ------------- | ----------------------------------------------------------------------------------------- | ------------------------------- | ------------ | | `pixverse-v6` | text, one image, first + last frame, 1–7 reference images, a completed `pixverse-v6` task | `360p`, `540p`, `720p`, `1080p` | 1–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. For a single higher-detail shot from text or one image, see [PixVerse V6 Max](https://toklab.ai/docs/pixverse-v6-max). ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "pixverse-v6", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "540p", "duration": 5, "size": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "pixverse-v6", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "540p", "duration": 5, "size": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'pixverse-v6', prompt: 'A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.', resolution: '540p', duration: 5, size: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "pixverse-v6", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "540p", "duration": 5, "size": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | ---------------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `pixverse-v6` | | `prompt` | string | required | Up to 5,000 characters. Required in every mode. | | `resolution` | enum | `540p` | `360p`, `540p`, `720p` or `1080p`. | | `duration` | integer | `5` | 1–15 seconds. A first/last frame transition takes only `5` or `8`. | | `size` | enum | `16:9` | `16:9`, `4:3`, `1:1`, `3:4`, `9:16`, `2:3`, `3:2` or `21:9`. Used by text to video and multi-image reference; other modes follow their images. | | `audio` | boolean | `false` | Generate native audio. Billed at the audio rate. | | `seed` | integer | none | 0–2147483647. The same request and seed give similar results. | | `negative_prompt` | string | none | What to keep out of the clip. Up to 2,048 characters. | | `watermark` | boolean | `false` | Add a watermark. | | `motion_mode` | enum | `normal` | Only `normal` is supported. | | `generate_multi_clip_switch` | boolean | `false` | Multi-clip generation. Text and image to video only. | | `image_urls` | URL list | none | Image to video. The first image is used. | | `first_frame_image` | URL | none | Transition: the first frame. Send it with `last_frame_image`. | | `last_frame_image` | URL | none | Transition: the last frame. Send it with `first_frame_image`. | | `img_references` | URL list | none | Multi-image reference: 1–7 images. | | `extend_from_task_id` | string | none | Extend: the ID of one of your completed `pixverse-v6` tasks. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead. ## Modes The fields you send pick the mode. Send the fields of one mode per request. | Mode | Send | Notes | | --------------------- | ---------------------------------------- | ------------------------------------------------------------------------------ | | Text to video | no image or extend fields | `size` sets the shape. | | Image to video | `image_urls` | The clip starts from the first image. | | Transition | `first_frame_image` + `last_frame_image` | 5 or 8 seconds. | | Multi-image reference | `img_references` (1–7 URLs) | Combines characters, objects or scenes from the images; `size` sets the shape. | | Extend | `extend_from_task_id` | Continues a completed `pixverse-v6` task of yours. | ```json { "model": "pixverse-v6", "prompt": "The puppy slowly turns into a kitten, soft studio light.", "first_frame_image": "https://example.com/puppy.jpg", "last_frame_image": "https://example.com/kitten.jpg", "duration": 5 } ``` ```json { "model": "pixverse-v6", "prompt": "The paper boat drifts on toward a lily pad.", "extend_from_task_id": "task_...", "resolution": "540p", "duration": 5 } ``` An extend returns the source clip followed by the new segment, and bills only the new segment's `duration`. In our test, a 1-second extend of a 1-second clip came back 2.1 seconds long and was billed for 1 second. ## Media inputs Images are public HTTP(S) URLs. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use JPG, PNG or WebP images of 20 MB or less. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. PixVerse V6 is billed per second of video, at a rate set by the resolution and by whether audio is generated: ```text cost = duration × rate per second for the resolution and audio setting ``` Every mode costs the same per second; an extend bills only the new segment. The duration is known when the request is accepted, so the amount reserved is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "pixverse-v6", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "pixverse-v6", "status": "completed", "created_at": 1789689600, "finished_at": 1789689640, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests 1-second `360p` `16:9` clips came back as MP4 (H.264) at 640 × 360, 36–45 seconds after submission. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "pixverse-v6", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, place, camera move and light in the prompt; name the sounds you want when `audio` is on. * Draft at `360p` or `540p`, then render the final shot at `1080p` with the same request and `seed`. * For vertical video, send `size: "9:16"` with text to video, or a portrait image. * Add `no text, no logos` to keep invented marks out. ## Related * [PixVerse V6 pricing](https://toklab.ai/pricing) * [PixVerse V6 Max API reference](https://toklab.ai/docs/pixverse-v6-max) * [Download OpenAPI](https://toklab.ai/docs/pixverse-v6.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/pixverse-v6.md) --- Source: https://toklab.ai/docs/pixverse-v6-max PixVerse V6 Max is the higher-detail version of PixVerse V6. It makes a 1–15 second clip from a prompt, or from one starting image with an optional prompt, at 360p, 540p, 720p or 1080p, with optional native audio. Send the request, keep the returned task ID, and read the finished video from the task. Images go in as URLs. ## Model IDs | Model ID | Inputs | Resolutions | Length | | ----------------- | --------------- | ------------------------------- | ------------ | | `pixverse-v6-max` | text, one image | `360p`, `540p`, `720p`, `1080p` | 1–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. Transitions, multi-image reference and extend are [PixVerse V6](https://toklab.ai/docs/pixverse-v6) features. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "pixverse-v6-max", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "pixverse-v6-max", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'pixverse-v6-max', prompt: 'A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.', resolution: '720p', duration: 5, aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "pixverse-v6-max", "prompt": "A red paper boat drifting on a calm pond at sunrise, soft mist, slow push-in. No text, no logos.", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | -------------- | -------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `pixverse-v6-max` | | `prompt` | string | see notes | Text to video: required, up to 5,000 characters. With an image: optional, up to 2,048 characters. | | `image_urls` | URL list | none | Image to video: exactly one image. Without it the clip is text to video. | | `resolution` | enum | `540p` | `360p`, `540p`, `720p` or `1080p`. | | `quality` | enum | none | Alias of `resolution`, same values. `resolution` wins when both are sent. | | `duration` | integer | `5` | 1–15 seconds. | | `aspect_ratio` | enum | `16:9` | `16:9`, `4:3`, `1:1`, `3:4`, `9:16`, `2:3`, `3:2` or `21:9`. Text to video only; with an image the clip follows the image. | | `audio` | boolean | `false` | Generate native audio. Billed at the audio rate. | | `seed` | integer | none | 0–2147483647. The same request and seed give similar results. | The schema is strict: unknown fields are rejected rather than ignored. `first_frame_image`, `last_frame_image`, `img_references` and `extend_from_task_id` return a 400 that points to `pixverse-v6`. `callback_url` is not available; poll the task instead. ## Image to video Pass one image in `image_urls`. The clip starts from it and keeps its shape, so a portrait image gives a portrait clip. The prompt is optional here. ```json { "model": "pixverse-v6-max", "prompt": "The subject slowly turns toward the camera, soft natural light.", "image_urls": ["https://example.com/start.png"], "resolution": "1080p", "duration": 5 } ``` ## Media inputs The image is a public HTTP(S) URL. Base64 data URIs are not accepted: upload the file to your own storage and pass its URL. Use a JPG, PNG or WebP image of 20 MB or less, at most 10,000 pixels on each side. ## Pricing dimensions Check the [pricing page](https://toklab.ai/pricing) for current rates. PixVerse V6 Max is billed per second of video, at a rate set by the resolution and by whether audio is generated: ```text cost = duration × rate per second for the resolution and audio setting ``` Text to video and image to video cost the same. The duration is known when the request is accepted, so the amount reserved is the amount charged. View final charges in your account usage history. Failed tasks are not charged. ## Output schema Submission returns the task: ```json {"id": "task_...", "model": "pixverse-v6-max", "status": "processing", "created_at": 1789689600} ``` ### Get the task ```text GET https://api.toklab.ai/v1/tasks/{task_id} ``` Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress. ### Completed task ```json { "id": "task_...", "model": "pixverse-v6-max", "status": "completed", "created_at": 1789689600, "finished_at": 1789689690, "output": { "video_url": "https://cdn.example.com/media/tasks/task_example/0.mp4" } } ``` In our tests 1-second `360p` `16:9` clips came back as MP4 (H.264) at 640 × 360, 81–89 seconds after submission. ## Errors Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object. See the [shared error catalog](https://toklab.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance. ```json { "id": "task_...", "model": "pixverse-v6-max", "status": "failed", "error": { "code": 60001, "message": "The request was rejected by the content policy. Please revise the prompt or input images." } } ``` If submission itself times out, check your tasks before submitting again: the first request may have been accepted. ## Tips * Describe subject, place, camera move and light in the prompt; name the sounds you want when `audio` is on. * Draft at `360p` or `540p`, then render the final shot at `1080p` with the same request and `seed`. * For vertical video, send `aspect_ratio: "9:16"`, or a portrait image. * Add `no text, no logos` to keep invented marks out. ## Related * [PixVerse V6 Max pricing](https://toklab.ai/pricing) * [PixVerse V6 API reference](https://toklab.ai/docs/pixverse-v6) * [Download OpenAPI](https://toklab.ai/docs/pixverse-v6-max.openapi.json) * [Copyable Markdown](https://toklab.ai/docs/pixverse-v6-max.md) --- Source: https://toklab.ai/docs/sd-video SD Video is TokLab's video generation model, built on MiniMax H3. One request makes the whole scene, picture and sound together: a 5–15 second clip with its own dialogue, ambience and effects. Send the request, keep the returned task ID, and read the finished video from the task. First frames and references go in as URLs. ## Model IDs | Model ID | Modes | Resolutions | Length | | ---------- | ------------------------------------------------------- | ----------- | ------------ | | `sd-video` | text\_to\_video, image\_to\_video, reference\_to\_video | 480p, 768p | 5–15 seconds | See the [pricing page](https://toklab.ai/pricing) for current prices. ## Quick example ```bash curl https://api.toklab.ai/v1/videos/generations \ -H "Authorization: Bearer $TOKLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "sd-video", "mode": "text_to_video", "prompt": "A lighthouse keeper in a wool coat stands on a wet stone pier at dawn and says, \"The fog lifts at seven.\" Locked-off shot, waves slapping the stones, no music.", "duration": 5, "resolution": "768p", "aspect_ratio": "16:9" }' ``` ```python import os import requests response = requests.post( "https://api.toklab.ai/v1/videos/generations", headers={"Authorization": f"Bearer {os.environ['TOKLAB_API_KEY']}"}, json={ "model": "sd-video", "mode": "text_to_video", "prompt": "A lighthouse keeper in a wool coat stands on a wet stone pier at dawn and says, \"The fog lifts at seven.\" Locked-off shot, waves slapping the stones, no music.", "duration": 5, "resolution": "768p", "aspect_ratio": "16:9", }, timeout=60, ) response.raise_for_status() task_id = response.json()["id"] ``` ```javascript const response = await fetch('https://api.toklab.ai/v1/videos/generations', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOKLAB_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'sd-video', mode: 'text_to_video', prompt: 'A lighthouse keeper in a wool coat stands on a wet stone pier at dawn and says, "The fog lifts at seven." Locked-off shot, waves slapping the stones, no music.', duration: 5, resolution: '768p', aspect_ratio: '16:9', }), }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { id: taskId } = await response.json(); ``` ```go package main import ( "encoding/json" "fmt" "net/http" "os" "strings" "time" ) func main() { body := strings.NewReader(`{ "model": "sd-video", "mode": "text_to_video", "prompt": "A lighthouse keeper in a wool coat stands on a wet stone pier at dawn and says, \"The fog lifts at seven.\" Locked-off shot, waves slapping the stones, no music.", "duration": 5, "resolution": "768p", "aspect_ratio": "16:9" }`) req, err := http.NewRequest("POST", "https://api.toklab.ai/v1/videos/generations", body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer " + os.Getenv("TOKLAB_API_KEY")) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 60 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { panic(res.Status) } var task struct { ID string `json:"id"` } if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) } fmt.Println(task.ID) } ``` ## Endpoint ```text POST https://api.toklab.ai/v1/videos/generations ``` | Header | Value | | ------------- | --------------------- | | Authorization | `Bearer YOUR_API_KEY` | | Content-Type | `application/json` | The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code. ## Parameters | Field | Type | Default | Notes | | -------------------- | --------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | required | `sd-video` | | `mode` | enum | `reference_to_video` | `text_to_video`, `image_to_video`, `reference_to_video`. The short forms `t2v`, `i2v` and `ref2va` are accepted. | | `prompt` | string | required | 1 to 32,000 characters. Describes the picture and the sound. | | `duration` | integer | `5` | Any integer from 5 to 15 seconds. | | `resolution` | enum | `768p` | `480p` or `768p`. | | `aspect_ratio` | enum | by mode | `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`, plus `adaptive` in `reference_to_video`. `image_to_video` follows the first frame. | | `prompt_enhancement` | enum | `turbo` | `turbo`, `quality` or `disabled`. | | `seed` | integer | random | Unsigned 32-bit. Set it to repeat a shot. | | `image` | reference | | `image_to_video` only, required there. The first frame. | | `reference_images` | array | `[]` | `reference_to_video` only. Up to 9. | | `reference_videos` | array | `[]` | `reference_to_video` only. Up to 3. | | `reference_audio` | array | `[]` | `reference_to_video` only. Up to 3. | The schema is strict: unknown fields are rejected rather than ignored. `callback_url` and `callback_id` are not available; poll the task instead. ## Modes `mode` selects how the model is conditioned. Each mode has its own fields; a field from another mode returns 400 when it carries a value (an empty list or `null` passes). | Mode | Requires | Takes | | ------------------------------ | -------------------------------------------------- | --------------------------------------------------------- | | `text_to_video` | `prompt` | the shared fields | | `image_to_video` | `prompt` and `image` | `image` as the first frame | | `reference_to_video` (default) | `prompt` and at least one reference image or video | `reference_images`, `reference_videos`, `reference_audio` | `image_to_video` treats the image as the literal first frame, so the clip opens exactly as that still looks. To place a product or a person into a scene of your own, use `reference_to_video` and describe the scene around it. ### References and prompt labels In `reference_to_video`, list order becomes the label you use in the prompt. The first entry of `reference_images` is ``, the second is ``; the first entry of `reference_videos` is `