Beta

This API is in beta. Endpoints, request/response formats, and behavior may change without notice.

API Reference

Terramind Documentation

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

modelstringrequired

Model ID. See the Models page for the full list.

messagesarrayrequired

Array of message objects. Each message has role ( "user" | "assistant") and content (string). For images/files, use parts array.

systemstring

Custom system prompt. Defaults to "You are a helpful assistant."

streamboolean

Set to false for a non-streaming JSON response. Defaults to true.

temperaturenumber

Sampling temperature (0–2). Higher values make output more random.

maxTokensnumber

Maximum number of output tokens.

top_pnumber

Nucleus sampling (0–1). Alternative to temperature.

frequency_penaltynumber

Frequency penalty (−2 to 2). Positive values reduce repetition.

presence_penaltynumber

Presence penalty (−2 to 2). Positive values encourage new topics.

stopstring[]

Up to 4 stop sequences. Generation stops when any is encountered.

seedinteger

Integer seed for reproducible output (best-effort, provider-dependent).

reasoningEffortstring

For reasoning models: "low", "medium", "high", or "xhigh".

toolsarray

Tool definitions for function calling. Each tool has name, description, and parameters (JSON Schema).

tool_choicestring | object

Tool selection: "auto", "none", "required", or { "type": "tool", "toolName": "..." }.

response_formatobject

Output format: { "type": "json_object" } for JSON mode, or { "type": "json_schema", "schema": {...} } for structured output.

fallbacksstring[]

Up to 5 fallback model IDs. If the primary model fails, each fallback is tried in order. The response model field reflects the model that actually served the request.

timeoutinteger

Request timeout in milliseconds (1000–300000). For streaming, acts as a time-to-first-token (TTFT) timeout. Returns 408 if no model responds in time.

max_stepsinteger

Maximum number of LLM round-trips for tool use (1–10). Each step allows the model to call tools and receive results before generating the next response. Defaults to 3 when any server-executed tool is active, 1 otherwise.

Example Request

cURL
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",
    "messages": [
      {"role": "user", "content": "Explain quantum computing in 3 sentences."}
    ],
    "system": "You are a physics professor."
  }'
Try it liveclaude-haiku-4-5

Non-Streaming Response

Set "stream": false to receive a complete JSON response instead of a stream:

Response
{
  "id": "a1b2c3d4-...",
  "model": "claude-sonnet-4-6",
  "content": "Quantum computing uses qubits...",
  "usage": {
    "inputTokens": 42,
    "outputTokens": 128,
    "totalTokens": 170
  },
  "creditsConsumed": 0.0023
}
Try it livenon-streaming

Image Input

Send images as base64 data URLs in the parts array:

JSON body
{
  "model": "claude-sonnet-4-6",
  "messages": [{
    "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..."
      }
    ]
  }]
}
Try it liveimage vision
Preview

Video Input

Send video as a base64 data URL or a publicly accessible URL in the parts array. Only models with supportsVideo: true accept video input (e.g. Gemini models).

JSON body
{
  "model": "gemini-3.1-pro-preview",
  "messages": [{
    "role": "user",
    "content": "Describe what happens in this video.",
    "parts": [
      { "type": "text", "text": "Describe what happens in this video." },
      {
        "type": "file",
        "mediaType": "video/mp4",
        "url": "data:video/mp4;base64,AAAAIGZ0eXBpc29..."
      }
    ]
  }]
}

Supported formats: video/mp4, video/webm, video/quicktime. Check supportsVideo in the Models response to see which models accept video.

Try it livevideo vision

Audio Input

Send audio as a base64 data URL or a publicly accessible URL in the parts array. Only models with supportsAudio: true accept audio input (e.g. Gemini models, GPT-4o).

JSON body
{
  "model": "gemini-3.1-pro-preview",
  "messages": [{
    "role": "user",
    "content": "Transcribe and summarize this audio.",
    "parts": [
      { "type": "text", "text": "Transcribe and summarize this audio." },
      {
        "type": "file",
        "mediaType": "audio/mpeg",
        "url": "data:audio/mpeg;base64,SUQzBAAAAAAAI1RT..."
      }
    ]
  }]
}

Supported formats: audio/mpeg, audio/wav, audio/webm, audio/ogg, audio/flac. Check supportsAudio in the Models response to see which models accept audio.

Try it liveaudio transcription

Tools / Function Calling

Define tools for the model to call. Tool calls are returned to the client for execution — the API does not execute tools.

Request with tools
{
  "model": "claude-sonnet-4-6",
  "stream": false,
  "messages": [{"role": "user", "content": "Toggle the website theme."}],
  "tools": [{
    "name": "theme_change",
    "description": "Toggle the website color theme between light and dark",
    "parameters": {
      "type": "object",
      "properties": {
        "theme": { "type": "string", "enum": ["light", "dark"], "description": "The target theme" }
      },
      "required": ["theme"]
    }
  }],
  "tool_choice": "auto"
}

When the model calls a tool, the non-streaming response includes a toolCalls array. In streaming mode, tool calls appear as message parts automatically.

Response with tool call
{
  "id": "...",
  "model": "claude-sonnet-4-6",
  "content": "",
  "toolCalls": [{
    "toolCallId": "call_abc123",
    "toolName": "theme_change",
    "args": { "theme": "dark" }
  }],
  "usage": { "inputTokens": 56, "outputTokens": 24, "totalTokens": 80 },
  "creditsConsumed": 0.0012
}

Try it — clicking Run will ask the model to toggle this page's theme via a tool call, and the theme will actually change:

Try it livetheme change tool

JSON Mode

Force the model to respond with valid JSON using response_format.

JSON object mode
{
  "model": "claude-sonnet-4-6",
  "stream": false,
  "response_format": { "type": "json_object" },
  "messages": [{"role": "user", "content": "List 3 colors as JSON"}]
}

For structured output with a specific schema, use json_schema. The validated result is returned in the parsed field:

Structured output
{
  "model": "claude-sonnet-4-6",
  "stream": false,
  "response_format": {
    "type": "json_schema",
    "schema": {
      "type": "object",
      "properties": {
        "colors": { "type": "array", "items": { "type": "string" } }
      },
      "required": ["colors"]
    }
  },
  "messages": [{"role": "user", "content": "List 3 primary colors"}]
}
Try it liveJSON mode

Model Fallbacks

Provide up to 5 fallback models. If the primary model fails or times out, each fallback is tried in order until one succeeds.

Request with fallbacks
{
  "model": "claude-sonnet-4-6",
  "stream": false,
  "fallbacks": ["claude-haiku-4-5"],
  "messages": [{"role": "user", "content": "Hello"}]
}

When a fallback model serves the request, the response model field reflects the actual model used. In streaming mode, an X-Model-Id header is also included. If all models fail, the API returns 502.

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 (1,000–300,000). For streaming requests, the timeout acts as a time-to-first-token (TTFT) deadline — it is cleared once the first chunk arrives.

Request with timeout
{
  "model": "claude-sonnet-4-6",
  "stream": false,
  "timeout": 10000,
  "messages": [{"role": "user", "content": "Hello"}]
}

When combined with fallbacks, each model gets its own timeout. If all models time out, the API returns 408.

Server-Executed Tools

A set of built-in tool names is 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 name outside 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:

Request with web search
{
  "model": "claude-sonnet-4-6",
  "messages": [{"role": "user", "content": "What happened in tech news today?"}],
  "tools": [{"name": "web_search"}]
}

You can combine multiple server tools, and mix them with user-defined tools in the same request. When any server-executed tool is present, max_steps defaults to 3 so the model can call tools and then summarize. Credits for each tool call are deducted from your organization's balance in addition to the model's token cost.

Tool nameWhat it doesPrice
web_searchReal-time web search.$0.01 per search
retrieveFetch a URL and return cleaned markdown.$0.001 per retrieval
image_searchImage search.$0.01 per search
video_searchVideo search.$0.02 per search
shop_searchShopping search.$0.003 per search
search_twitterLive search over Twitter/X posts.$0.025 per source used
get_weatherCurrent weather + forecast for a city.$0.0005 per request
code_execExecute Python or TypeScript in a sandbox.$0.01 per execution
generate_imageGenerate an image.$0.10–$0.30 per image (model-dependent)
generate_videoGenerate a video from text or image.$0.20–$2.00 per second (model-dependent)
generate_audioGenerate speech, music, sound effects, or multi-speaker dialogue.Variable (per character / per second)
understand_videoAnalyze video content (YouTube, GCS, or direct URL).Variable (per token usage)
stock_chartStock prices, news, SEC filings, financial statements, dividends, insider transactions, and market movers.Variable (per provider call usage)
Combining multiple server tools
{
  "model": "claude-sonnet-4-6",
  "messages": [{"role": "user", "content": "Check SF weather, then compute avg temp for the next 3 days."}],
  "tools": [{"name": "get_weather"}, {"name": "code_exec"}]
}
Try it liveweb search

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 normally.

cURL with gzip
echo '{"model":"claude-sonnet-4-6","messages":[{"role":"user","content":"Hello!"}]}' | 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 @-

The official TypeScript and Python SDKs compress requests automatically. To disable, set compression: false when creating the client.

Streaming Response

By default, returns a streaming response in Vercel AI SDK UI Message Stream Protocol. Use with useChat from @ai-sdk/react for seamless integration.

Usage Metadata

Token usage and credit consumption are included in the assistant message metadata at the end of the stream:

Message metadata
{
  "usage": {
    "inputTokens": 42,
    "outputTokens": 128,
    "totalTokens": 170,
    "cacheReadInputTokens": 0,
    "cacheCreationInputTokens": 0
  },
  "creditsConsumed": 0.0023
}

Billing & Credit Reservation

Before any tokens are generated, the server reserves a worst-case credit estimate (based on the input token count and your maxTokens cap) against the organization's balance. When the stream finishes, that reservation is settled against the actual token usage — the difference is refunded if the model generated fewer tokens than reserved. If the request fails (provider error, aborted stream, timeout) the full reservation is released. Concurrent requests against the same balance are guarded atomically so they cannot double-spend.

If the reserved amount would push the org over its 6-hour usage window, the request is rejected before work starts with 429 and error code WINDOW_EXHAUSTED (with a resetAt timestamp). See Credit Reservation for details.