DocsAPI keys

Requests

Tools

One tool loop that works on every provider. Call ids and result pairing differ underneath — Anthropic refuses punctuation Gemini puts in an id — and that is handled, so changing the model does not change your code.

Declaring a tool

parameters is ordinary JSON Schema. Check the catalog first: sending tools to a model whose capabilities.toolUse is false is refused with 422 before any provider is called.

"tools": [
  {
    "name": "getWeather",
    "description": "Current conditions for a city.",
    "parameters": {
      "type": "object",
      "properties": { "city": { "type": "string", "description": "City name" } },
      "required": ["city"]
    }
  }
]

The full loop

Four steps. The turn you get back is appended to messages verbatim, the tool result goes after it paired on the call's id, and you send the whole thing again. Nothing is rewritten by hand.

1. Ask

{
  "model": "claude-sonnet-5",
  "systemPrompt": "Use tools when they help.",
  "messages": [{ "type": "user", "value": "What is the weather in Lagos?" }],
  "tools": [ … ],
  "parameters": { "maxTokens": 1024 }
}

2. The model calls

{
  "type": "monolith",
  "model": { "name": "claude-sonnet-5", "tier": "high", "publisher": "Anthropic", "provider": "Anthropic" },
  "messages": [
    { "type": "content", "value": "Let me check.", "data": {} },
    { "type": "toolCall", "call": { "id": "toolu_01A", "name": "getWeather", "arguments": "{\"city\":\"Lagos\"}" } }
  ],
  "usage": { "finishReason": "tool_use" }
}

3. Run it and answer

{
  "model": "claude-sonnet-5",
  "systemPrompt": "Use tools when they help.",
  "messages": [
    { "type": "user", "value": "What is the weather in Lagos?" },
    { "type": "content", "value": "Let me check." },
    { "type": "toolCall", "call": { "id": "toolu_01A", "name": "getWeather", "arguments": "{\"city\":\"Lagos\"}" } },
    { "type": "toolResult", "result": { "id": "toolu_01A", "name": "getWeather", "content": "31C, humid, scattered thunderstorms" } }
  ],
  "tools": [ … ]
}

4. The answer

{
  "type": "monolith",
  "messages": [
    { "type": "content", "value": "It is 31C and humid in Lagos, with scattered thunderstorms.", "data": {} }
  ],
  "usage": { "finishReason": "end_turn" }
}

arguments is a string Not an object. That is what every provider sends and what they expect back. name travels beside id because some providers pair a result by name while others pair by id.

When a tool fails

Report it as a result rather than inventing prose. The pairing is unchanged; failure is what tells the model the call did not succeed, and content stays whatever the tool produced.

{
  "type": "toolResult",
  "result": {
    "id": "toolu_01A",
    "name": "getWeather",
    "content": "upstream timed out",
    "failure": { "success": false, "code": 504, "message": "The weather service did not answer." }
  }
}

Forcing or forbidding a call

parameters.toolUse decides whether the model may call, must call, or must not.

Value Meaning
{ "type": "auto" } The model decides. The default.
{ "type": "none" } The model may not call a tool, even though tools are declared.
{ "type": "any" } The model must call one of the declared tools.
{ "type": "use", "toolCall": { … } } The model must call the named tool and no other. toolCall is a full tool declaration, not just a name.

Structured output

To hold the answer to a JSON Schema instead, send responseSchema. See structured output.

Files returned by tools

A tool result can carry files in result.documents; the same file-source and processing rules apply as to files on a user message. See files and file processing for the public source shape, native model capabilities, none, auto, directed, and the named processor catalog.

Updated Oct 6, 2026
Esc