API reference

POST /v1/conversation — multi-turn chat

Send the whole thread each time: alternating user and assistant turns, content blocks, temperature and tools. Reference and examples for the SubToAPI conversation endpoint.

Updated

The conversation endpoint is stateless: you send the full history with every call and get the next assistant turn back. That keeps your data in your hands and makes retries trivial.

terminal
curl -X POST \
  "https://api.subtoapi.app/v1/conversation" \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "system": "You are a concise assistant.",
    "model": "balanced",
    "messages": [
      { "role": "user", "content": "What is a Durable Object?" },
      { "role": "assistant", "content": "A single-instance, strongly consistent object on Cloudflare." },
      { "role": "user", "content": "Give me a one-line use case." }
    ],
    "temperature": 0.3
  }'
chat.ts
type Msg = { role: "user" | "assistant"; content: string };

export async function chat(messages: Msg[]) {
  const res = await fetch("https://api.subtoapi.app/v1/conversation", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      system: "You are a concise assistant.",
      messages,
      model: "balanced",
      temperature: 0.3,
    }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(`${data.error}: ${data.message}`);
  return data.content
    .filter((b: { type: string }) => b.type === "text")
    .map((b: { text: string }) => b.text)
    .join("");
}

Request body

Fields
messagesrequired
Message[]
Alternating user/assistant turns, oldest first. Max 200.
system
string
Instructions for the whole thread.
tools
ToolDefinition[]
Tool definitions with a JSON Schema input_schema. Max 50 per request.
tool_choice
object
{ "type": "auto" } (default), { "type": "any" }, { "type": "none" } or { "type": "tool", "name": "…" }.
model
"fast" | "balanced" | "best"
Public model alias for this call.
temperature
number
Optional sampling temperature.
thinking_budget
number
Optional extended-thinking budget where supported.

Content blocks

content may be a plain string or an array of blocks. Text blocks are { "type": "text", "text": "…" }; assistant turns can contain tool_use blocks and user turns can carry tool_result blocks — see tool use.

Response

Same shape as /v1/messages: content blocks, usage, latency_ms, model, provider, request_id and stop_reason.

200 OK (tool call)
{
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_...",
      "name": "get_weather",
      "input": { "city": "Frankfurt" }
    }
  ],
  "stop_reason": "tool_use",
  "usage": {
    "input_tokens": 780,
    "output_tokens": 32,
    "cache_read_tokens": 0,
    "cache_write_tokens": 0,
    "total_tokens": 812
  },
  "model": "balanced",
  "provider": "claude",
  "request_id": "req_..."
}

Keep threads lean

Long histories cost input tokens on every call. Summarise older turns into the system prompt once a thread grows; the limit is 200 messages per request.

Frequently asked questions

Do I have to alternate user and assistant turns?
Yes. Start with a user message and alternate; two user messages in a row are rejected with 422 invalid_request.
Can I set temperature?
Yes, temperature between 0 and 1. Lower values are more deterministic; omit it for the provider default.