## Function calling (tools)

Describe the functions the model may call, and it decides on its own when a call is needed. The model does not run the function — it returns its name and arguments, and your code performs the call. You send the result back into the conversation, and the model composes the final answer.

When the model decides to call a function, `finish_reason` is `tool_calls` and `content` is `null`. The arguments arrive in `tool_calls[].function.arguments` as a JSON string.

## Function description

```bash
curl -X POST https://vibecode.bitrix24.com/v1/chat/completions \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bitrix/bitrixgpt-5.5",
    "messages": [
      {"role": "user", "content": "What is the weather in Berlin?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Get the current weather in the specified city",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string", "description": "City name"}
            },
            "required": ["city"]
          }
        }
      }
    ],
    "tool_choice": "auto"
  }'
```

## Response example

```json
{
  "id": "chatcmpl-9aaee7576d8057ab",
  "object": "chat.completion",
  "model": "bitrix/bitrixgpt-5.5",
  "choices": [
    {
      "index": 0,
      "finish_reason": "tool_calls",
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "chatcmpl-tool-a423212c4e614cab",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\": \"Berlin\"}"
            }
          }
        ]
      }
    }
  ],
  "usage": {"prompt_tokens": 275, "completion_tokens": 26, "total_tokens": 301}
}
```

## Returning the result to the conversation

Run the function on your side and add a message with the `tool` role and the same `tool_call_id` to `messages`:

```json
{
  "messages": [
    {"role": "user", "content": "What is the weather in Berlin?"},
    {"role": "assistant", "content": null, "tool_calls": [{"id": "chatcmpl-tool-a423212c4e614cab", "type": "function", "function": {"name": "get_weather", "arguments": "{\"city\": \"Berlin\"}"}}]},
    {"role": "tool", "tool_call_id": "chatcmpl-tool-a423212c4e614cab", "content": "+5°C, cloudy"}
  ]
}
```

In its next response the model composes human-readable text based on the returned result.

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `unsupported_tool_type` | The `tools` array contains an element with a `type` other than `function`. For web search use [`POST /v1/search`](/docs/search/run) |
| 400 | `tool_choice_without_tools` | `tool_choice` was passed, but the `tools` array is absent |

The full list of common API errors — [Errors](/docs/errors).

## Known specifics

**Only `type: "function"` is supported.** The endpoint has no built-in tools such as web search. A request with a different `type` value is rejected with `400` rather than silently executed without tools.

**Names in the response are checked against your list.** If the model invents a function name that is not in `tools`, that call is removed from the response. When all calls turn out to be invented, `finish_reason` switches to `stop` and a textual explanation arrives in `content` — the conversation does not loop on a nonexistent function.

**Arguments arrive as a string.** The `arguments` field is JSON as a string, and you must parse it before use. The model can return syntactically valid JSON that does not match your parameter schema, so validate the values before the call.

## See also

- [Create a chat completion](./completions.md)
- [Guaranteed JSON response](./json.md)
- [Web search](/docs/search/run)
- [List of models](/docs/ai/models/list)
