Guides

Function tools

Let an agent call your API, transfer the call, end it or send an SMS during a conversation.

A function tool is something the agent's LLM may decide to do mid-call. You describe when to use it and what arguments it takes; the platform makes the request and gives the result back to the model.

In the dashboard: Agent Studio → Tools tab.

Where tools live

Tools are part of the conversation task: agent_config.tasks[i].tools_config.api_tools. It has two parts: tools (what the LLM sees) and tools_params (how each tool is carried out), matched by name.

json
{
  "tools": [
    {"name": "check_order_status", "key": "custom_task",
     "description": "Use when the customer asks about the status of an order.",
     "pre_call_message": "Let me check that for you.",
     "parameters": {"type": "object",
                    "properties": {"order_id": {"type": "string", "description": "The order number"}},
                    "required": ["order_id"]}}
  ],
  "tools_params": {
    "check_order_status": {
      "method": "GET",
      "url": "https://api.example.test/orders",
      "api_token": "Bearer <your token>",
      "headers": {"X-Source": "voice"},
      "param": {"order_id": "%(order_id)s"}
    }
  }
}

Tool kinds

keyWhat it does
custom_taskAn HTTP request to your API
check_availability_of_slots, book_appointmentCalendar-style tools. They are plain HTTP tools with ready-made parameter templates; you supply the URL
transfer_callHands the caller to a person. Needs param.call_transfer_number: an E.164 phone number. A SIP URI is stored but refused when the call tries to transfer
end_callEnds the call. Needs no tools_params entry
send_smsTexts the person on the call. Needs param.message (at most 1,000 characters)

Rules checked on save

  • name: letters, digits, _ and -, at most 64 characters, unique.
  • description: required. It tells the LLM when to call the tool.
  • parameters: a JSON schema of type object; property types string, integer, number, boolean, array, object; required must name existing properties.
  • method: GET, POST, PUT, PATCH or DELETE (default POST).
  • url: an http(s) URL, required for the three HTTP kinds.
  • scope: global (default) or node with a list of existing node ids, for graph agents.

A failure is a 400 with the path, for example agent_config.tasks.0.tools_config.api_tools.tools.0.description is required: it tells the LLM when to call 'check_order_status'.

How a request is built

  • api_token is sent verbatim as the Authorization header.
  • param becomes the query string for GET and DELETE, and the JSON body otherwise.
  • Placeholders %(name)s, %(name)i and %(name)f are filled from the tool's arguments, then agent_id, call_sid, to_number, from_number, the call's user_data and values a graph has collected. An unknown placeholder becomes an empty string.
  • The request has a 10 second timeout and does not follow redirects.

URLs into private networks are refused

Before every tool request the URL is resolved. If it points at a private, loopback, link-local, reserved or multicast address the request is not sent and the tool result is an error starting with blocked:. This also applies to pre-call webhooks. Operators can lift it for local development only.

Helper endpoints

These help you build a tool before saving it. See Function tools reference.

EndpointUse
GET /tools/catalogTemplates for each kind, the allowed keys and methods. send_sms is listed under extra_tools
POST /tools/validateCheck one tool or a whole api_tools object
POST /tools/from-curlTurn a pasted cURL command into a tool
POST /tools/testRun the tool's request once and see the answer

The helper endpoints use the dashboard's form: one object per tool, with its tools_params entry under value.

bash
curl -X POST https://api.kshyamai.space/tools/from-curl \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"curl": "curl -H \"Authorization: Bearer abc\" https://api.example.test/orders?order_id=ORD-1"}'

The method, URL, headers and query or body fields become parameters, and Authorization moves to api_token. Errors: curl is required: paste a cURL command, The command must start with curl, The cURL command has no http(s) URL.

Test a tool

bash
curl -X POST https://api.kshyamai.space/tools/test \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "3c90c3cc-0d44-4b50-8822-8dd25736052a", "name": "check_order_status",
       "arguments": {"order_id": "ORD-1"}}'
json
{
  "ok": true, "status_code": 200, "body": {"status": "delivered"}, "error": null, "duration_ms": 12,
  "request": {"method": "GET", "url": "https://api.example.test/orders?order_id=ORD-1",
              "headers": {"Content-Type": "application/json", "Authorization": "**********", "X-Source": "voice"},
              "body": null}
}

This makes the real request. An API that answers non-2xx, or cannot be reached, still gives 200 with ok: false and error. A 400 means the request never went out: arguments.order_id is required by this function, Only tools that call an API can be tested; transfer_call does not make a request, or The function's url is not allowed: ....

Pre-call webhooks

There are two different things with this name.

  • Per tool: set pre_call_webhook_param on a tool's params. Just before the tool runs, the platform posts the execution plus those fields to pre_call_webhook_url, or to the agent's webhook_url if none is set. A failing endpoint never fails the tool.
  • Per call: agent_config.pre_call_webhook_url (or agent_data.pre_call_webhook_url on one call) is posted the execution before dialing. If it answers with a JSON object within 5 seconds, its keys are merged into the call's variables. A failure never stops the call.

Tool call logs

Every tool run is recorded on the execution as tool_call_logs:

json
[{"name": "check_order_status", "key": "custom_task", "arguments": {"order_id": "ORD-1"},
  "status": "success", "result": {"status": "delivered"}, "status_code": 200, "duration_ms": 12,
  "at": "2026-10-13T09:30:02.114000+00:00"}]

Results longer than 5,000 characters are cut. The raw logs also get a request and a response entry under component function_call, with credentials masked. A transfer fills transfer_call_data on the execution. See Post-call data.

send_sms

The text comes from the tool's param.message, not from the LLM. It is sent once per call and text, and only if the do-not-call list, consent (when required), the do-not-disturb check and the agent's calling hours all allow it. Otherwise the tool result is {"sent": false, "reason": "..."}. The test chat never sends.

Limitations

  • The two calendar kinds are generic HTTP tools. There is no built-in calendar provider integration.
  • On the own engine, a transfer is reported and handed to the telephony provider; it has not been proven on a live call. The own engine does not fire per-tool pre-call webhooks; the mock engine and the test chat do.
  • send_sms sends during the call, not after it, and real SMS providers have only been tested against local fakes. See Compliance.
  • Agents saved before secrets were encrypted may still hold api_token in plain text until the operator runs the rotation script.