Skip to main content
During a call the assistant can invoke functions you define — check availability, look up an account, transfer a call, hang up. You declare the tools once per call and CallingBox runs a short model → tool → model loop whenever the model decides to call one.
V1 supports native tools (HTTP endpoints you host, plus a small set of platform built-ins). MCP-hosted tools are a planned follow-up.

When to use tools

Tools are useful when the model needs information or actions that live outside the call — live data, writes to your system, or control over the call itself. If a piece of information never changes and fits in the prompt, put it in context instead. Reach for a tool when the answer:
  • Changes between calls (availability, account balances, order status)
  • Requires a write (book an appointment, create a ticket)
  • Controls the call (hang up, transfer)
Keep tool counts small. In V1 you can attach up to 16 tools per call, but a receptionist typically only needs 2–4.

Tool types

HTTP tools

The model calls your HTTPS endpoint with a JSON body matching the parameter schema. You return a small JSON result.

Built-in tools

Platform-owned actions like end_call. No network hop. Safe to attach when you want the agent to be able to hang up on its own.

Defining tools

The SDKs ship with typed authoring helpers so you don’t hand-write JSON schema. Both languages produce identical wire payloads.
import { CallingBox, tool } from "callingbox";

const cb = new CallingBox({ apiKey: process.env.CALLINGBOX_API_KEY! });

const checkAvailability = tool.http({
  name: "check_availability",
  description: "Look up open appointment slots for a given date.",
  policy: "read",
  url: "https://api.example.com/callingbox/check-availability",
  parameters: tool.object({
    date: tool.string("Date in YYYY-MM-DD format"),
  }, { required: ["date"] }),
});

const endCall = tool.builtin({
  name: "end_call",
  description: "Politely hang up when the caller is done.",
});

await cb.calls.create({
  phoneNumberId: "pn_...",
  to: "+15551234567",
  prompt: "You are a receptionist for Acme Dental.",
  tools: [checkAvailability, endCall],
});
If you prefer raw JSON, pass an array matching the wire format directly. The dashboard “New call” form also accepts pasted JSON under Optional API fields → Tools.

Tool policies

Every tool has a policy:
  • read — the model can invoke the tool whenever it thinks the answer is useful. Use for lookups.
  • confirm_first_write — the model must get a clear affirmative from the caller on the previous turn before CallingBox will execute the tool. Use for writes (bookings, charges, cancellations). If the caller has not confirmed, CallingBox returns a confirmation_required envelope and the model asks again.
Default to read for lookups and confirm_first_write for anything that mutates state.

Writing good tool descriptions

The model picks tools based on their name and description. Treat these like API docs written for a junior teammate — a few clear sentences beat a paragraph of adjectives.
Good
name: book_appointment
description: Book a single appointment slot returned by check_availability.
  Call this only after the caller has confirmed the date, time, and their name.
Avoid
name: book
description: Books stuff.
Tips that consistently improve tool selection:
  1. State the purpose and a precondition. “Call only after the caller has confirmed the date and time.”
  2. Name the output shape in the description when it affects follow-up turns (“Returns an { available: boolean, slots: string[] } object.”).
  3. Be explicit about what the tool is not. “Does not cancel existing appointments — use cancel_appointment for that.”
  4. Use snake_case names and keep them under 40 characters.
  5. Keep parameter schemas tight. Required fields should be truly required; add additionalProperties: false on objects.

Writing a prompt that uses tools

The prompt is where you tell the agent when to reach for each tool. A good tool-aware prompt has four parts:
  1. Role + goal — who the agent is and what success looks like.
  2. Tool cues — when to call each tool in plain English.
  3. Confirmation rules — when to read something back before acting.
  4. Failure handling — what to do if a tool errors or returns nothing.

Receptionist example

You are Nina, the receptionist for Acme Dental. Callers want to book,
reschedule, or ask about their appointments.

How to use tools:
- Use check_availability as soon as the caller names a date. Read two
  slots back to them before asking which works.
- Use book_appointment only after the caller has clearly said "yes"
  to a specific slot. Always include their full name.
- Use end_call once the caller confirms the appointment is booked or
  says they have nothing else.

If a tool returns no slots, apologize briefly and offer the next day.
If a tool errors, tell the caller you're having trouble and offer to
have a human call them back. Never invent appointment times.

Keep responses under two sentences. Do not spell out times digit by digit.
This pattern — role, tool cues, confirmation, failure — scales up to more complex agents without losing the model’s ability to pick the right tool.

What you see in the trace

Every tool invocation shows up in the call timeline with:
  • The tool name and arguments the model produced
  • The HTTP status (for http tools) or the built-in action taken
  • Latency and whether the call succeeded
  • Any error message returned to the model
Use the trace to catch “model picked the wrong tool” bugs early — usually that’s a signal to tighten a description or rename a tool.

Limits and behavior

  • Up to 16 tools per call.
  • Up to 2 tool rounds per user turn — if the model tries to chain more than that, CallingBox falls back to a plain reply so the call stays responsive.
  • HTTP tools must use HTTPS and cannot point at private or loopback addresses.
  • Tools are disabled on voicemail drops. Built-ins like end_call still run; HTTP tools are suppressed when the call is answered by a machine and the voicemail action is leave_message.