# Terramind API > Terramind provides a unified API for accessing 100+ AI models from Anthropic, OpenAI, Google, xAI, DeepSeek, and more — all through a single endpoint. > **Beta**: This API is currently in beta. Endpoints, request/response formats, and behavior may change without notice. Pin to specific model IDs and test against updates before deploying to production. ## Base URL ``` https://terramind.com/api/v1 ``` ## Authentication All API requests require a Terramind API key. Get yours at Settings > API Keys in the Terramind dashboard. Include your key in the `Authorization` header: ``` Authorization: Bearer sk-tm-YOUR_KEY_HERE ``` ## Chat Endpoint ### POST /api/v1/chat Send messages to any supported model. Returns a streaming response by default, or a JSON response when `stream: false`. **Request body:** ```json { "model": "claude-sonnet-4-6", "messages": [ { "role": "user", "content": "Hello, world!" } ], "system": "You are a helpful assistant.", "stream": true, "temperature": 0.7, "maxTokens": 4096, "top_p": 0.9, "frequency_penalty": 0.5, "presence_penalty": 0.0, "stop": ["\n\n"], "seed": 42, "reasoningEffort": "medium", "max_steps": 3 } ``` **Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | model | string | Yes | Model ID (see /api/v1/models) | | messages | array | Yes | Array of message objects with `role` and `content` | | system | string | No | Custom system prompt | | stream | boolean | No | Set to `false` for non-streaming JSON response. Default: `true` | | temperature | number | No | Sampling temperature (0-2) | | maxTokens | number | No | Maximum output tokens | | top_p | number | No | Nucleus sampling (0-1). Alternative to temperature | | frequency_penalty | number | No | Frequency penalty (-2 to 2). Reduce repetition | | presence_penalty | number | No | Presence penalty (-2 to 2). Encourage new topics | | stop | string[] | No | Up to 4 stop sequences | | seed | integer | No | Integer seed for reproducible output (best-effort) | | reasoningEffort | string | No | For reasoning models: "low", "medium", "high", "xhigh" | | tools | array | No | Tool definitions for function calling (see below) | | tool_choice | string/object | No | "auto", "none", "required", or `{ "type": "tool", "toolName": "..." }` | | response_format | object | No | `{ "type": "json_object" }` or `{ "type": "json_schema", "schema": {...} }` | | fallbacks | string[] | No | Up to 5 fallback model IDs. Tried in order if primary fails. | | timeout | integer | No | Request timeout in ms (1000–300000). TTFT timeout for streaming. | | max_steps | integer | No | Max LLM round-trips for tool use (1–10). Default: 3 when any server-executed tool is active, 1 otherwise. | **Message format:** Messages support text, images, video, and audio attachments via the `parts` array: ```json { "role": "user", "content": "What's in this image?", "parts": [ { "type": "text", "text": "What's in this image?" }, { "type": "file", "mediaType": "image/png", "url": "data:image/png;base64,iVBORw0KGgo..." } ] } ``` **Video input** (models with `supportsVideo: true`, e.g. Gemini, Helium): ```json { "role": "user", "parts": [ { "type": "text", "text": "Describe what happens in this video." }, { "type": "file", "mediaType": "video/mp4", "url": "data:video/mp4;base64,AAAAIGZ0eXBpc29..." } ] } ``` Supported video formats: `video/mp4`, `video/webm`, `video/quicktime`. **Audio input** (models with `supportsAudio: true`, e.g. Gemini, Helium, GPT-4o): ```json { "role": "user", "parts": [ { "type": "text", "text": "Transcribe and summarize this audio." }, { "type": "file", "mediaType": "audio/mpeg", "url": "data:audio/mpeg;base64,SUQzBAAAAAAAI1RT..." } ] } ``` Supported audio formats: `audio/mpeg`, `audio/wav`, `audio/webm`, `audio/ogg`, `audio/flac`. **Non-streaming response** (`stream: false`): ```json { "id": "a1b2c3d4-...", "model": "claude-sonnet-4-6", "content": "Quantum computing uses qubits...", "usage": { "inputTokens": 42, "outputTokens": 128, "totalTokens": 170 }, "creditsConsumed": 0.0023 } ``` Before generation starts, a worst-case credit estimate is reserved against your organization's balance; after the response completes, the reservation is settled against actual token usage. Failed or aborted requests release the full reservation. Requests blocked by the 6-hour usage window return `429 WINDOW_EXHAUSTED` with a `resetAt` timestamp. See [Credit Reservation](#credit-reservation). **Streaming response** (default): Streaming response in Vercel AI SDK UI Message Stream format. Compatible with the `useChat` hook from `@ai-sdk/react`. Token usage and credit consumption are included in the assistant message metadata: ```json { "usage": { "inputTokens": 42, "outputTokens": 128, "totalTokens": 170, "cacheReadInputTokens": 0, "cacheCreationInputTokens": 0 }, "creditsConsumed": 0.0023 } ``` ## Tools / Function Calling Define tools for the model to call. Tool calls are returned to the client — the API does not execute tools. ```json { "model": "claude-sonnet-4-6", "stream": false, "messages": [{"role": "user", "content": "What's the weather in London?"}], "tools": [{ "name": "get_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } }], "tool_choice": "auto" } ``` Response with tool call: ```json { "id": "...", "model": "claude-sonnet-4-6", "content": "", "toolCalls": [{ "toolCallId": "call_abc123", "toolName": "get_weather", "args": { "city": "London" } }], "usage": { "inputTokens": 56, "outputTokens": 24, "totalTokens": 80 } } ``` ## JSON Mode Force JSON output with `response_format`: - `{ "type": "json_object" }` — model responds with valid JSON - `{ "type": "json_schema", "schema": {...} }` — structured output validated against your schema (result in `parsed` field) ## Model Fallbacks Provide up to 5 fallback models. If the primary model fails, each fallback is tried in order: ```json { "model": "claude-sonnet-4-6", "fallbacks": ["claude-haiku-4-5"], "stream": false, "messages": [{"role": "user", "content": "Hello"}] } ``` The response `model` field reflects the actual model that served. In streaming, an `X-Model-Id` header is included when a fallback served. Returns `502` if all models fail. **Streaming limitation:** Fallback only applies before the stream starts. Once tokens are flowing, a mid-stream failure cannot fall back to another model. ## Request Timeout Set a timeout in milliseconds (1000–300000). For streaming, acts as a time-to-first-token (TTFT) deadline — cleared once the first chunk arrives. When combined with fallbacks, each model gets its own timeout. Returns `408` if all models time out. ```json { "timeout": 10000, "model": "claude-sonnet-4-6", "stream": false, "messages": [...] } ``` ## Server-Executed Tools Certain tool names are executed server-side: the API runs the tool, feeds the result back into the model, and the final assistant message is what you receive. Any tool you name that isn't in this list is treated as a user-defined pass-through and returned as a `toolCalls` entry for your client to execute. Include the tool by name (no `description` or `parameters` needed — the server uses the built-in schema): ```json { "model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "What happened in tech news today?"}], "tools": [{"name": "web_search"}] } ``` Multiple server tools can be combined, and they can be mixed with user-defined tools in the same `tools` array. When any server-executed tool is present, `max_steps` defaults to 3 so the model can call tools and then summarize. Override with `max_steps` (1–10). Credits for each tool call are deducted from your organization's balance in addition to the model's token cost. | Tool name | What it does | Price | |-----------|--------------|-------| | `web_search` | Real-time web search. | $0.01 per search | | `retrieve` | Fetch a URL and return cleaned markdown. | $0.001 per retrieval | | `image_search` | Image search. | $0.01 per search | | `video_search` | Video search. | $0.02 per search | | `shop_search` | Shopping search. | $0.003 per search | | `search_twitter` | Live search over Twitter/X posts. | $0.025 per source used | | `get_weather` | Current weather + forecast for a city. | $0.0005 per request | | `code_exec` | Execute Python or TypeScript in a sandbox. | $0.01 per execution | | `generate_image` | Generate an image. | $0.10–$0.30 per image (model-dependent) | | `generate_video` | Generate a video from text or image. | $0.20–$2.00 per second (model-dependent) | | `generate_audio` | Generate speech, music, sound effects, or multi-speaker dialogue. | Variable (per character / per second) | | `understand_video` | Analyze video content (YouTube, GCS, or direct URL). | Variable (per token usage) | | `stock_chart` | Stock prices, news, SEC filings, financial statements, dividends, insider transactions, and market movers. | Variable (per provider call usage) | ```json { "model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "Check SF weather, then compute average temp for the next 3 days."}], "tools": [{"name": "get_weather"}, {"name": "code_exec"}] } ``` ## Anthropic Provider Tools (Computer Use, Bash, Text Editor) Anthropic exposes a small set of provider-defined tools that ride on the model's training (computer-use, bash, text editor). The API forwards these tool calls **back to your client** to execute — same behavior as user-defined pass-through tools — and automatically attaches the required `anthropic-beta` header so the model can emit them. **Requires a Claude model** (e.g. `claude-sonnet-4-6`, `claude-opus-5-5`); requesting an Anthropic provider tool with a non-Claude model returns 400. Declare them by setting `type` on the tool spec to one of the version strings below. The `name` field is whatever your client wants to receive in the resulting `tool_call` (Anthropic's docs use canonical names like `computer`, `bash`, `str_replace_based_edit_tool`). | `type` | Anthropic name | Required `parameters` | Supported models | |--------|----------------|------------------------|------------------| | `computer_20251124` | `computer` | `displayWidthPx`, `displayHeightPx`, optional `displayNumber`, optional `enableZoom` | Opus 4.8, Opus 4.7, Opus 4.6, Sonnet 4.6, Opus 4.5 | | `computer_20250124` | `computer` | `displayWidthPx`, `displayHeightPx`, optional `displayNumber` | Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus 4 | | `bash_20250124` | `bash` | none | Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus 4 | | `text_editor_20250728` | `str_replace_based_edit_tool` | optional `maxCharacters` | Claude 4.x family (Sonnet 4.6, Opus 4.6/4.7/4.8, Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus 4) | > **Pick the matching computer-use version for your model.** `computer_20251124` (Nov 2025) is the latest — it adds the `zoom` action (set `parameters.enableZoom: true` to enable) and uses beta header `computer-use-2025-11-24`. Use `computer_20250124` for older Sonnet 4.5 / Haiku 4.5 / Opus 4.x / Sonnet 4 / Opus 4 (beta header `computer-use-2025-01-24`). Older variants (`computer_20241022`, `bash_20241022`, `text_editor_20250124`) target deprecated Claude 3.5/3.7 models and are not exposed. Computer-use example (Sonnet 4.6 with zoom enabled): ```json { "model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "Open the calculator and compute 12 × 34."}], "tools": [ { "name": "computer", "type": "computer_20251124", "parameters": { "displayWidthPx": 1920, "displayHeightPx": 1080, "displayNumber": 1, "enableZoom": true } } ], "max_steps": 10 } ``` When the model emits a tool call (e.g. `screenshot`, `left_click`, `type`, `zoom`), your client executes the action against the controlled environment and returns the result on the next turn. For multi-turn loops (typical for computer-use), bump `max_steps` (1–30) so the API gives the model multiple sampling rounds before stopping. Mix Anthropic provider tools with server-executed tools (`web_search`, etc.) and your own pass-through tools freely — they all coexist in `tools[]`. ## SDK Compatibility (OpenAI / Anthropic Drop-In) Terramind exposes three additional endpoints that match the wire format of OpenAI and Anthropic exactly, so existing apps can switch by changing two things: the base URL and the API key. Model IDs stay Terramind IDs (e.g. `claude-sonnet-4-6`, `gpt-5.5`) — there is no model-name aliasing. The exact same auth, credit reservation, 6-hour window, fallback, timeout, and pricing rules apply as `/api/v1/chat`; only the request/response shape differs. | Endpoint | Mirrors | Notes | |----------|---------|-------| | `POST /api/v1/chat/completions` | OpenAI Chat Completions | Streaming + non-streaming. Forwards `logit_bias`, `logprobs`/`top_logprobs`, `metadata`, `store`, `service_tier`, `prediction`, `modalities`, `audio`, `web_search_options` via providerOptions. Surfaces `system_fingerprint`, `service_tier`, audio + prediction token details on the response. Rejects `n > 1` with 400. | | `POST /api/v1/completions` | OpenAI legacy text completions | `echo: true` prepends the prompt. `logprobs` (0–5) forwarded. `suffix` is rejected with 400 (no provider supports it). | | `POST /api/v1/messages` | Anthropic Messages | Streaming + non-streaming. Supports `cache_control` with `ttl: '5m'\|'1h'` on system / tools / messages / images / tool_results, Files API `file_id` sources, documents with `citations: { enabled: true }`, `service_tier`, `mcp_servers`, extended thinking with `signature_delta` replay, and Anthropic server tools (`web_search_20250305`, `code_execution_20250522`, `computer_20251124`/`20250124`, `bash_20250124`, `text_editor_20250728`). Streams emit `signature_delta` + `citations_delta` events. Usage breakdown includes `cache_creation.{ephemeral_5m_input_tokens, ephemeral_1h_input_tokens}`. | | `POST /api/v1/messages/count_tokens` | Anthropic count_tokens | Returns `{ "input_tokens": N }` for the request without invoking the model. Does not consume credits. | Authentication is the same `Authorization: Bearer sk-tm-...` header. The OpenAI SDK sets it via `apiKey:`; the Anthropic SDK accepts it via `apiKey:` or `authToken:` — either works. Credits, gating, and the 402 / 429 contracts behave identically across all four endpoints. Error bodies follow the upstream SDK's conventions: OpenAI-style `{ "error": { "message": "...", "type": "..." } }` for `/v1/chat/completions` and `/v1/completions` (see [OpenAI-compatible error types](#openai-compatible-error-types-v1chatcompletions)); Anthropic-style `{ "type": "error", "error": { "type": "...", "message": "..." } }` for `/v1/messages`. BYOK (bring your own key) does **not** apply to these endpoints — they always charge against your organization's Terramind balance. BYOK is a separate ingestion-only path for Claude Code / Codex usage reporting and does not gate inference requests. ## Models Endpoint ### GET /api/v1/models Returns a list of all available models with pricing and capability information. **Response:** ```json { "models": [ { "id": "claude-sonnet-4-6", "name": "Claude Sonnet 4.6", "cost": { "input": 3.00, "output": 15.00 }, "limit": { "context": 200000, "output": 16384 }, "supportsImages": true, "description": "General purpose, coding" }, { "id": "gemini-3.1-pro-preview", "name": "Gemini 3.1 Pro Preview", "cost": { "input": 2.00, "output": 12.00 }, "limit": { "context": 1048576, "output": 65536 }, "reasoning": true, "supportsImages": true, "supportsVideo": true, "supportsAudio": true } ] } ``` **Fields:** | Field | Type | Description | |-------|------|-------------| | id | string | Model identifier. Pass as `model` in the chat endpoint. | | name | string | Human-readable model name. | | cost | object | `input` and `output` pricing in USD per 1M tokens. | | limit | object | `context` (max input tokens) and `output` (max output tokens). | | reasoning | boolean? | `true` for models that support extended thinking. | | supportsImages | boolean? | `true` for models that accept image inputs. | | supportsVideo | boolean? | `true` for models that accept video inputs (e.g. Gemini). | | supportsAudio | boolean? | `true` for models that accept audio inputs (e.g. Gemini, GPT-4o). | | description | string? | Short description of the model's strengths. | ## API Key Management ### POST /api/v1/api-keys Create a new API key. Requires Firebase authentication (browser session, not API key auth). Max 10 keys per user. The full key is returned only once — store it securely. **Request body:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | name | string | Yes | Display name for the key (1-64 characters) | | expiresAt | number | No | Expiration as Unix timestamp in milliseconds. Must be in the future. | ```json { "name": "My production app", "expiresAt": 1735689600000 } ``` **Response:** ```json { "key": "sk-tm-a1b2c3d4...", "keyId": "a1b2c3d4e5f6", "keyPrefix": "sk-tm-a1b2...", "name": "My production app", "createdAt": 1712000000000, "message": "Save this key securely. It will not be shown again." } ``` ### GET /api/v1/api-keys List all API keys for the authenticated user. Returns metadata only — never the full key. **Response:** ```json { "keys": [ { "keyId": "a1b2c3d4e5f6", "keyPrefix": "sk-tm-a1b2...", "name": "My production app", "createdAt": 1712000000000, "expiresAt": 1735689600000 } ] } ``` ### DELETE /api/v1/api-keys/{keyId} Revoke a specific API key. The key is soft-deleted for audit trail. **Response:** ```json { "success": true, "keyId": "a1b2c3d4e5f6" } ``` ## Usage & Credits ### GET /api/v1/usage Returns your organization's credit balance and recent API usage history. **Query parameters:** | Parameter | Type | Description | |-----------|------|-------------| | limit | integer | Records to return (1-100, default 10) | | after | string | ISO 8601 date. Only return records after this timestamp. | **Example:** ```bash curl https://terramind.com/api/v1/usage?limit=5 \ -H "Authorization: Bearer sk-tm-YOUR_KEY" ``` **Response:** ```json { "credits": { "balance": 45230.5 }, "recentUsage": [ { "id": "abc123", "creditsUsed": 0.0023, "usageType": "model", "details": { "modelName": "claude-sonnet-4-6", "inputTokens": 42, "outputTokens": 128, "totalTokens": 170 }, "timestamp": "2026-04-14T10:30:00.000Z" } ] } ``` Only API usage records are returned (`source: "api"`). Response includes `Cache-Control: no-store`. ## Request Compression The API supports gzip-compressed request bodies. This is recommended for large payloads (long conversations, tool results, file attachments) and is enabled by default in the official SDKs. To compress a request, gzip the JSON body and set the `Content-Encoding: gzip` header. The server auto-detects and decompresses. Uncompressed JSON requests continue to work as before. ```bash # cURL with gzip compression echo '{"model":"claude-sonnet-4-6","messages":[...]}' | gzip | \ curl -X POST https://terramind.com/api/v1/chat \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -H "Content-Encoding: gzip" \ --data-binary @- ``` SDK compression is on by default. To disable: ```typescript // TypeScript const client = new Terramind({ apiKey: "sk-tm-...", compression: false }); ``` ```python # Python client = Terramind(api_key="sk-tm-...", compression=False) ``` ## Error Codes | Code | Meaning | |------|---------| | 400 | Invalid request (missing model, empty messages, invalid parameters, context overflow) | | 401 | Invalid or expired API key | | 402 | Insufficient credits | | 403 | Model requires a paid plan / no organization | | 408 | Request timed out (all models exceeded the `timeout`) | | 429 | Rate limit exceeded (check `Retry-After` header), OR the organization has hit its 6-hour usage window (error code `WINDOW_EXHAUSTED`, includes `resetAt` ISO-8601 timestamp — top up credits or wait for the window to reset) | | 500 | Internal server error | | 502 | All models failed (primary + all fallbacks exhausted) | Studio error body shape: ```json { "success": false, "error": { "code": "WINDOW_EXHAUSTED", "message": "...", "resetAt": "2026-04-23T18:00:00.000Z" } } ``` Error `code` values: `INVALID_INPUT`, `UNAUTHORIZED`, `INSUFFICIENT_CREDITS`, `WINDOW_EXHAUSTED`, `PROVIDER_ERROR`, `STORAGE_ERROR`, `CONFIG_ERROR`. ### OpenAI-compatible error types (`/v1/chat/completions`) The OpenAI-compatible endpoint wraps errors as `{ "error": { "message": "...", "type": "..." } }`: | Status | `type` | |--------|--------| | 400 | `invalid_request_error` | | 401 | `invalid_request_error` | | 402 | `insufficient_quota` | | 429 | `rate_limit_exceeded` | | 5xx | `api_error` | ## Credit Reservation Every billed endpoint reserves credits up-front before starting work and settles the reservation on completion, so concurrent requests cannot oversell the same balance: - **Chat / completions** — a worst-case estimate (from input tokens + `maxTokens`) is reserved when the request is accepted, then settled against the actual token usage in `onFinish`. If the stream errors or is aborted, the full reservation is released. - **Image & video generate / edit** — the fixed per-model cost is reserved at request time. Synchronous paths charge on a successful 2xx response and release on any 4xx/5xx or thrown error. Asynchronous jobs (`async: true` / HTTP 202) keep the reservation held until the fal webhook fires — successful delivery charges, any failure path (provider error, missing output, download or upload failure) releases. - **Webhooks** — deliveries are idempotent: the job is claimed atomically before settlement, so retried webhook deliveries never double-charge or double-release. Practical consequences for callers: - A `402 INSUFFICIENT_CREDITS` or `429 WINDOW_EXHAUSTED` returned before work starts means zero credits were used — the reservation never took hold. - The `credits.remaining` value in a success response reflects the balance *after* settlement. - For async image/video jobs you will only see the credit decrement after the webhook fires and the job transitions to `completed`. ## Response Headers All API responses include: | Header | Description | |--------|-------------| | X-Request-Id | Unique request identifier for debugging | | X-RateLimit-Limit | Maximum requests per minute (60) | | X-RateLimit-Remaining | Remaining requests in current window | | X-RateLimit-Reset | Unix timestamp (seconds) when rate limit resets | | X-Model-Id | Model that served the request (only when a fallback was used) | Rate limit headers are included for API key requests only. ## Rate Limits - 60 requests per minute per API key - Credits are deducted from your organization's balance ## Popular Models | Model | Best For | |-------|----------| | claude-sonnet-4-6 | General purpose, coding | | claude-fable-5-1 | Anthropic's most capable model — demanding reasoning, long-horizon agentic work | | claude-opus-5-5 | Complex reasoning, coding, long-running agent tasks | | claude-opus-5-5-fast | Opus 5.5 intelligence with faster output (2x price) | | claude-haiku-4-5 | Fast, lightweight | | gpt-6-astra | OpenAI's most capable — complex reasoning, coding, computer use, research | | gpt-6-astra-fast | Astra intelligence with faster output (2x price) | | gpt-6-sol | Complex professional workflows and sustained coding | | gpt-6-sol-fast | Sol intelligence with faster output (2x price) | | gpt-6-luna | Lower-cost GPT-6 for high-volume agentic workflows | | gpt-6-luna-fast | Luna throughput with faster output (2x price) | | gpt-5.6-terra | Balanced GPT-5.6 — previous-gen performance at a fraction of the cost | | gemini-3.1-pro-preview | Multimodal, long context | | gemini-3.8-flash | Coding, agentic loops, tunable thinking | | gemini-3.5-flash-lite | Fast, cheap subagents in complex workflows | | grok-4.7 | xAI's flagship — long-running agents, interactive and visual work | | grok-build-0.1 | Fast agentic coding | | muse-spark-1.1 | Meta's agentic model for tool use and parallel sub-agents | | deepseek-v4-flash-vision | Multimodal V4 Flash — vision-dependent agent workflows, 1M context | | deepseek-v4-1-flash | Natively multimodal V4.1 Flash — 1M context, Flash-tier pricing | | deepseek-v4-pro | DeepSeek flagship — reasoning, 1M context | | qwen3.8-max | Alibaba's 2.4T MoE flagship — autonomous coding, vision, 1M context | | qwen3.8-27b | Compact Qwen 3.8 — vision, thinking control, 262K context | | qwen3.8-2.4t-a95b | Open-weight Qwen 3.8 flagship — thinking-only, 262K context | | glm-5.3 | Z.ai's coding and agent model — complex software engineering, 1M context | | glm-5.3-flash | Z.ai's cheap multimodal coder — visual coding, 1M context | | glm-5.3-flashx | Z.ai's multimodal visual coder — code, browsers, documents, GUIs, 1M context | ### Evaluation Pass these model IDs to `/api/v1/evaluate`, not `/api/v1/chat`. Evaluation models take shared state plus typed questions and return choices, scores and boolean probabilities instead of text, so they will 400 on the chat endpoint. | Model | Best For | |-------|----------| | jev | TypeSafe AI's decision model — classification, routing, rubric scoring and automated verification. $0.042/1M input, output free | ```bash curl https://terramind.com/api/v1/evaluate \ -H "Authorization: Bearer $TERRAMIND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "jev", "state": "The support agent issued a full refund to the customer.", "questions": { "refunded": { "type": "boolean", "instructions": "Was a refund issued?" } } }' ``` Each key in `questions` becomes a key in `answers`. Question types are `boolean` (returns `probability`), `choice` (`criteria` is an object of at least two named options; returns the selected `choice` plus per-option `probabilities`) and `score` (`criteria` is an ordered array of at least two labels, lowest first; returns an interpolated `score`). Several questions of different types can share one `state` in a single request. `state` accepts a string, object or array. ### Studio (Video & Image) Pass these model IDs to the corresponding Studio endpoint (`/api/v1/studio/video/generate` or `/api/v1/studio/image/generate`), not `/api/v1/chat`. | Model | Kind | Endpoint | Best For | |-------|------|----------|----------| | veo | video | studio/video/generate | Google Veo 3.1 — 4/6/8s with audio | | veo-fast | video | studio/video/generate | Google Veo 3.1 Fast — cheaper, no audio | | kling-3.0-std | video | studio/video/generate | Kling 3.0 Standard — 3-15s, audio | | kling-3.0-pro | video | studio/video/generate | Kling 3.0 Pro — 3-15s, audio | | kling-3.0-4k | video | studio/video/generate | Kling 3.0 — 4K output | | wan-2.6 | video | studio/video/generate | WAN 2.6 — 480p–1080p, audio | | wan-2.7 | video | studio/video/generate | WAN 2.7 — text/image/reference/edit-video, 720p/1080p, optional audio track | | seedance-2.0 | video | studio/video/generate | ByteDance Seedance 2.0 — 480p/720p, audio | | seedance-2.0-fast | video | studio/video/generate | Seedance Fast — cheaper | | seedance-2.5 | video | studio/video/generate | ByteDance Seedance 2.5 — text/image/reference-to-video, 4-30s, 480p/720p, native audio | | grok-video | video | studio/video/generate | xAI Grok Imagine Video | | grok-video-v1.5 | video | studio/video/generate | xAI Grok Imagine Video 1.5 — image-to-video only, 480p/720p | | pixverse-v6 | video | studio/video/generate | Pixverse v6 — 5/8s, up to 1080p | | nano-banana | image | studio/image/generate, /image/edit | Fast text-to-image + edit (Gemini Flash) | | nano-banana-pro | image | studio/image/generate | Higher-fidelity Gemini Pro, up to 4K | | seedream | image | studio/image/generate, /image/edit | ByteDance Seedream v4.5 | | imagen-ultra | image | studio/image/generate | Google Imagen 4 Ultra | | gpt-image | image | studio/image/generate | OpenAI GPT Image 1 | | gpt-image-mini | image | studio/image/generate | OpenAI GPT Image 1 Mini | | gpt-image-2 | image | studio/image/generate, /image/edit | OpenAI GPT Image 2 | | gpt-image-2.5-flare | image | studio/image/generate, /image/edit | OpenAI GPT Image 2.5 Flare — fast default tier, natural lighting, transparency | | gpt-image-2.5-sunburst | image | studio/image/generate, /image/edit | OpenAI GPT Image 2.5 Sunburst — precision tier, intricate detail, slower | | grok-imagine | image | studio/image/generate | xAI Grok Imagine | | topaz-upscale | image | studio/image/upscale | 2x/4x image upscale (fal.ai Topaz) | | remove-background | image | studio/image/remove-background | BiRefNet v2 background removal | ## Example: cURL (Non-streaming) ```bash curl -X POST https://terramind.com/api/v1/chat \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "stream": false, "messages": [{"role": "user", "content": "Hello!"}] }' ``` ## Example: Vercel AI SDK (TypeScript) ```typescript import { useChat } from "@ai-sdk/react"; const { messages, input, handleInputChange, handleSubmit } = useChat({ api: "https://terramind.com/api/v1/chat", headers: { Authorization: "Bearer sk-tm-YOUR_KEY", }, body: { model: "claude-sonnet-4-6", }, }); ``` ## Example: Node.js (Server-side) ```typescript import { streamText } from "ai"; import { createOpenAI } from "@ai-sdk/openai"; const terramind = createOpenAI({ baseURL: "https://terramind.com/api/v1", apiKey: "sk-tm-YOUR_KEY", }); const result = streamText({ model: terramind("claude-sonnet-4-6"), messages: [{ role: "user", content: "Hello!" }], }); for await (const chunk of result.textStream) { process.stdout.write(chunk); } ``` ## Example: Python (Non-streaming) ```python import requests response = requests.post( "https://terramind.com/api/v1/chat", headers={ "Authorization": "Bearer sk-tm-YOUR_KEY", "Content-Type": "application/json", }, json={ "model": "claude-sonnet-4-6", "stream": False, "messages": [{"role": "user", "content": "Hello!"}], }, ) data = response.json() print(data["content"]) ``` ## Storage Studio endpoints that take media (e.g. `audio/transcribe`, `image/batch`) accept a `fileUrl` pointing to already-hosted bytes. For local files, mint a signed URL, `PUT` the bytes directly to GCS, and pass the returned `fileUrl` to any Studio method. This bypasses the 4.5 MB inbound body limit on the Studio function boundary. ### POST /api/v1/storage/upload-url Mint a pair of signed URLs: a 15-minute `PUT` URL for uploading bytes directly to GCS, and a 24-hour `READ` URL that Studio endpoints can fetch post-auth. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | contentType | string | Yes | MIME type (e.g. `audio/mpeg`, `image/png`) | | purpose | string | Yes | One of `audio`, `image`, `video`, `file` — decides the storage subdirectory | ```bash # 1. Mint a signed URL curl -X POST https://terramind.com/api/v1/storage/upload-url \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "contentType": "audio/mpeg", "purpose": "audio" }' # 2. PUT the bytes directly to the signed URL curl -X PUT "" \ -H "Content-Type: audio/mpeg" \ --data-binary @recording.mp3 # 3. Call a Studio endpoint with the fileUrl curl -X POST https://terramind.com/api/v1/studio/audio/transcribe \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "audioUrl": "", "language": "en" }' ``` Response: `{ id, uploadUrl, fileUrl, storagePath, expiresAt, readExpiresAt }`. Both SDKs wrap this flow: pass a `Blob`/`File` (TypeScript) or `bytes` (Python) directly to `audio.transcribe`, or call `storage.uploadFile()` / `storage.upload_file()` when you need the `fileUrl` for other methods. ## Studio API The Studio API provides endpoints for generating and manipulating media — images, videos, audio, voiceovers, and music. All endpoints are under `/api/v1/studio/*` and use the same API key authentication. ### POST /api/v1/studio/image/generate Generate images from a text prompt. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | prompt | string | Yes | Image description (3–2000 chars) | | model | string | No | `nano-banana` (default), `nano-banana-pro`, `seedream`, `gpt-image`, `gpt-image-mini`, `gpt-image-2`, `gpt-image-2.5-flare`, `gpt-image-2.5-sunburst`, `gemini-imagen`, `imagen-ultra`, `grok-imagine` | | numImages | number | No | Number of images (1–10, varies by model) | | aspectRatio | string | No | e.g. "16:9", "1:1" | | outputFormat | string | No | `jpeg`, `png`, `webp` | | resolution | string | No | `1K`, `2K`, `4K` (nano-banana-pro only) | | width | number | No | Width in pixels (seedream) | | height | number | No | Height in pixels (seedream) | | seed | number | No | Reproducibility seed | | quality | string | No | `auto`, `low`, `medium`, `high` (gpt-image, gpt-image-2, gpt-image-2.5) | | background | string | No | `auto`, `transparent`, `opaque` (gpt-image, gpt-image-2, gpt-image-2.5) | | imageSize | string \| object | No | `square_hd`, `square`, `portrait_4_3`, `portrait_16_9`, `landscape_4_3`, `landscape_16_9`, or `{ width, height }` (gpt-image-2, gpt-image-2.5) | | imageUrls | string[] | No | Reference images — turns the call into an edit (nano-banana, nano-banana-pro, seedream, gpt-image-mini, gpt-image-2, gpt-image-2.5, grok-imagine) | ```bash curl -X POST https://terramind.com/api/v1/studio/image/generate \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "A sunset over mountains", "model": "nano-banana"}' ``` Credits are reserved at request time and charged only on success. Failures (provider error, invalid input, storage failure, aborted async job) release the reservation automatically. See [Credit Reservation](#credit-reservation). ### POST /api/v1/studio/image/edit Edit images with text instructions. JSON body with `prompt` (required), `imageUrls` (required, array of URLs), `model` (`nano-banana`, `seedream`, `gpt-image-2`, `gpt-image-2.5-flare` or `gpt-image-2.5-sunburst`). The GPT Image models additionally accept `quality`, `background`, `imageSize` and `maskUrl`. ### POST /api/v1/studio/image/upscale Upscale an image. JSON body with `imageUrl` (required), `scaleFactor` (2/4/6, default 2), `service` (`fal`/`clipdrop`), `model`, `faceEnhancement`, `persistToStorage`, `saveToLibrary`. ```bash curl -X POST https://terramind.com/api/v1/studio/image/upscale \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"imageUrl": "https://example.com/photo.png", "scaleFactor": 4, "persistToStorage": true}' ``` ### POST /api/v1/studio/image/remove-background Remove image background. JSON body with `imageUrl` (required), `model` (`General Use (Light)`/`General Use (Heavy)`/`Portrait`), `operatingResolution`, `refineForeground`, `persistToStorage`, `saveToLibrary`. ### POST /api/v1/studio/image/batch Batch process multiple images. JSON body: `operation` (`remove-background`/`upscale`, required), `imageUrls` (array of 1–10 URLs, required), `scaleFactor` (optional), `service` (optional, `fal` default). For local files, upload each via [`POST /api/v1/storage/upload-url`](#post-apiv1storageupload-url) and pass the returned `fileUrl`s. ```bash curl -X POST https://terramind.com/api/v1/studio/image/batch \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "operation": "upscale", "imageUrls": ["https://example.com/a.png", "https://example.com/b.png"], "scaleFactor": 2 }' ``` ### POST /api/v1/studio/video/generate Generate a video from a text prompt. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | prompt | string | Yes | Video description (1–4000 chars) | | model | string | Yes | `veo`, `veo-fast`, `kling-3.0-std`, `kling-3.0-pro`, `kling-3.0-4k`, `wan-2.6`, `wan-2.7`, `seedance-2.0`, `seedance-2.0-fast`, `seedance-2.5`, `grok-video`, `grok-video-v1.5`, `pixverse-v6` | | duration | number | No | Duration in seconds (Kling 3.0 accepts any integer 3–15) | | aspectRatio | string | No | `16:9`, `9:16`, `1:1` | | resolution | string | No | `480p`, `720p`, `1080p` (Kling 3.0 resolution is tier-locked — pick `kling-3.0-4k` for 4K) | | imageUrl | string | No | Image URL for image-to-video | | referenceImages | string[] | No | Kling 3.0 reference-to-video; up to 4 (std/pro) or 7 (4k) URLs. WAN 2.7: multi-image refs (≤9); entry [0] is also used as the reference for edit-video | | referenceVideos | string[] | No | WAN 2.7 multi-video refs (≤3); Seedance reference-to-video token-mapped video refs | | endImageUrl | string | No | End-frame image URL (Kling 3.0 image-to-video and WAN 2.7 image-to-video) | | sourceVideoUrl | string | No | Source video to transform (WAN 2.7 edit-video only) | | audioUrl | string | No | Audio track to condition output on (WAN 2.7 only) | | negativePrompt | string | No | What to avoid | | generateAudio | boolean | No | Include audio (Kling 3.0 default: true) | | cfgScale | number | No | Classifier-free guidance 0–1 (Kling 3.0 only; default 0.5) | | shotType | string | No | Kling 3.0 only: `customize` (default) or `intelligent` | | seed | number | No | Reproducibility seed | ```bash curl -X POST https://terramind.com/api/v1/studio/video/generate \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "A drone flying over a tropical island", "model": "veo", "duration": 5}' ``` Credits are reserved when the request is accepted and charged only after the video is successfully stored. Any failure (provider error, missing video URL, download/upload failure) releases the reservation. See [Credit Reservation](#credit-reservation). ### POST /api/v1/studio/video/remove-background Remove the background from a video using fal.ai VEED. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | videoUrl | string | Yes | Input video URL | | durationSeconds | number | Yes | Source duration in seconds (used for billing) | | variant | string | No | `standard` (default), `fast`, or `green-screen` | | backgroundColor | string | No | Hex/named color (green-screen variant only) | | persistToStorage | boolean | No | Re-upload to Terramind storage (default true) | ```bash curl -X POST https://terramind.com/api/v1/studio/video/remove-background \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"videoUrl": "https://example.com/clip.mp4", "durationSeconds": 8, "variant": "standard"}' ``` ### POST /api/v1/studio/video/upscale Upscale a video to a higher resolution using fal.ai Topaz, optionally interpolating to a higher target FPS. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | videoUrl | string | Yes | Input video URL | | durationSeconds | number | Yes | Source duration in seconds (used for billing) | | upscaleFactor | number | No | `2` (default) or `4` | | targetFps | number | No | `24`, `30`, `48`, or `60` | | persistToStorage | boolean | No | Re-upload to Terramind storage (default true) | ```bash curl -X POST https://terramind.com/api/v1/studio/video/upscale \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"videoUrl": "https://example.com/clip.mp4", "durationSeconds": 8, "upscaleFactor": 2}' ``` ### POST /api/v1/studio/audio/transcribe Transcribe audio to text using ElevenLabs Scribe. JSON body: `audioUrl` (required), `language` (optional), `fileName` (optional). For local files, upload via [`POST /api/v1/storage/upload-url`](#post-apiv1storageupload-url) and pass the returned `fileUrl` as `audioUrl`. Returns `{ success, data: { text, language_code, words }, credits }`. ```bash curl -X POST https://terramind.com/api/v1/studio/audio/transcribe \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "audioUrl": "https://example.com/recording.mp3", "language": "en" }' ``` ### POST /api/v1/studio/sfx/generate Generate sound effects from text. Fields: `prompt` (required), `title` (required), `duration` (0.5–22s, default 5), `promptInfluence` (0–1, default 0.3). ### POST /api/v1/studio/voiceover/generate Generate voiceover from text using ElevenLabs TTS. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | text | string | Yes | Text to speak (1–5000 chars) | | title | string | Yes | Voiceover title | | voice | string | No | Voice name (default: `george`). Options: rachelle, drew, clyde, paul, domi, dave, fin, sarah, antoni, thomas, charlie, george, emily, elli, callum, patrick, harry, liam, dorothy, josh, arnold, adam, sam | | stability | number | No | 0–1 (default: 0.5) | | similarityBoost | number | No | 0–1 (default: 0.5) | ### POST /api/v1/studio/dialogue/generate Generate multi-voice dialogue. Fields: `inputs` (array of `{text, voiceId}`), `title` (required), `stability`, `similarityBoost`. ```bash curl -X POST https://terramind.com/api/v1/studio/dialogue/generate \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"inputs": [{"text": "Hello!", "voiceId": "george"}, {"text": "Hi there!", "voiceId": "sarah"}], "title": "Demo"}' ``` ### POST /api/v1/studio/music/plan Generate a composition plan for music. Fields: `prompt` (required), `music_length_ms`, `source_composition_plan`, `model_id`. Returns structured composition with sections, styles, and durations. ### POST /api/v1/studio/music/generate Generate music from a prompt or composition plan. Fields: `prompt`, `composition_plan`, `durationSeconds` (default 30), `coverPrompt`, `force_instrumental` (default false), `model_id`, `mode` (`full`/`audio-only`). ```bash curl -X POST https://terramind.com/api/v1/studio/music/generate \ -H "Authorization: Bearer sk-tm-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Chill lo-fi hip hop beat", "durationSeconds": 60, "force_instrumental": true}' ``` ### Studio Response Format Most endpoints return: ```json { "success": true, "data": { "url": "...", "model": "...", ... }, "credits": { "used": 1, "cost": 5.0, "remaining": 9995.0 } } ``` Binary endpoints (upscale, remove-bg) return raw image bytes with `Content-Type: image/png`. ## Links - Dashboard: https://terramind.com - Pricing: https://terramind.com/pricing - API Docs: https://terramind.com/docs/api - OpenAPI 3.1 specification: https://terramind.com/openapi.json