Tools¶
A tool is a function the model can call mid-conversation: write a
summary, hit a webhook, search the knowledge base, hand a call to a human.
One exception is follow_up (category automation, covered in the table
below), which runs on its own schedule instead and is never something the
model calls. AiFlow ships a fixed catalog of built-in tools (this page),
plus two ways to add more without writing any AiFlow code:
Custom tools (any HTTP endpoint you control) and
MCP servers (any external Model Context Protocol
server). Enabling delegate_to_agent, covered below, is what actually
activates Agent-to-agent delegation on an agent once a
delegation link exists.
Admin role required
GET /api/v1/tools and GET /api/v1/agents/{agent_id}/tools need
any logged-in admin (Owner, Admin, Editor, or Viewer).
PUT /api/v1/agents/{agent_id}/tools/{tool_name}, which enables or
reconfigures a tool, needs Owner or Admin. That's a stricter tier
than editing the agent's own fields or context documents (both
Editor and above, see Agents and
Context & knowledge): changing what an
agent is capable of doing sits at a higher bar than changing what
it knows or says.
The tool registry¶
Returns every tool AiFlow's backend knows how to run, regardless of
whether any agent has it enabled. This is what the admin dashboard's Tools
tab reads to render a real form per tool (text fields, toggles, a masked
field for a secret) instead of a raw JSON textarea. config_schema is a
JSON Schema object describing exactly what
config a given tool accepts, and it's null for a tool that takes no
configuration at all.
Each entry in the returned list has this exact shape:
| Field | Type | Description |
|---|---|---|
name |
string | The tool's stable identifier, e.g. send_webhook. This is what you pass as {tool_name} in the enable endpoint below. |
description |
string | What the tool does, in the wording actually sent to the model as its function description. |
parameters |
object | The Gemini function-calling parameter schema the model fills in when it calls this tool. Not something you configure, shown for completeness. |
config_schema |
object or null |
The JSON Schema an admin's config value for this tool must satisfy. null for a tool that needs no configuration. |
display_name |
string or null |
Human-readable label for the admin UI, e.g. "Send Webhook". |
category |
string | One of built_in, custom, knowledge, messaging, orchestration, or automation. Grouping only, has no effect on behavior. |
A full entry, send_webhook, looks like this:
{
"name": "send_webhook",
"description": "Sends arbitrary structured data to an external system configured for this agent. Use this to notify a CRM, create a ticket, or trigger any other integration outside of AiFlow.",
"parameters": {
"type": "OBJECT",
"properties": {
"payload": {
"type": "OBJECT",
"description": "Arbitrary JSON data to send to the configured external system."
}
},
"required": ["payload"]
},
"config_schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"title": "Webhook URL",
"description": "The external endpoint AiFlow POSTs {agent_id, call_id, payload} to."
}
},
"required": ["url"]
},
"display_name": "Send Webhook",
"category": "custom"
}
delegate_to_orchestrator only appears when Orchestrators are turned on
This entry in the catalog is registered only when your deployment
has Orchestrators enabled, an opt-in, deployment-wide setting that's
off by default. Every other tool on this page is always present in
GET /api/v1/tools regardless of that setting.
An agent's current tool configuration¶
Returns the same catalog as GET /api/v1/tools, merged with this agent's
own enabled and config state: one entry per registered tool, whether
or not the agent has ever touched it:
Each entry adds two fields on top of the catalog shape above:
| Field | Type | Description |
|---|---|---|
tool_name |
string | Same identifier as name in the catalog. |
enabled |
boolean | true if this agent can call the tool right now. false for a tool the agent has never configured, this list always includes every registered tool, not just the ones turned on. |
config |
object or null |
This agent's stored config for the tool. null if never configured, even for a tool that requires config once enabled. |
Enabling or reconfiguring a tool¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled |
boolean | No | true |
Whether the agent can call this tool. |
config |
object or null |
No | null |
Must satisfy that tool's config_schema from the catalog. Omit or send null for a tool that takes no configuration. |
This endpoint always upserts. Calling it on a tool the agent has never
configured creates the row; calling it again replaces both enabled and
config in full. There is no partial-merge behavior the way PATCH
endpoints elsewhere on this site have: sending config without a
previously-set field means that field is gone, not preserved. A
{tool_name} that doesn't exist in the registry returns 404.
The examples below cover the tools most integrations touch first.
record_summary¶
No config. The agent writes a summary of the conversation onto the call record once it wraps up.
send_webhook¶
config.url (string, required by this tool's own config_schema): the
endpoint AiFlow POSTs {agent_id, call_id, payload} to whenever the model
calls this tool.
const response = await fetch(
"https://api.your-domain.com/api/v1/agents/1/tools/send_webhook",
{
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${adminToken}`,
},
body: JSON.stringify({
enabled: true,
config: { url: "https://hooks.example.com/acme" },
}),
},
);
search_knowledge_base¶
No config. Lets the model search this agent's own and every global context document (see Context & knowledge) for relevant passages.
search_skills¶
No config. Lets the model describe the current situation and get back the
closest-matching skill's full
procedure, plus the names and triggers of the agent's other skills, or a
clear "no matching skill" message. Passing a skill's exact name loads that
one alone, so a wrong first guess is one call away from the right
procedure. Distinct from search_knowledge_base: a knowledge-base match
is a short passage to quote, a skill match is a whole procedure to
follow.
send_whatsapp¶
config.content_sid (string, required by this tool's own config_schema):
a pre-approved Twilio Content Template SID (Twilio Console → Content
Template Builder). WhatsApp and Meta policy requires an approved template
for any business-initiated message; there's no free-form text option
here.
const response = await fetch(
"https://api.your-domain.com/api/v1/agents/1/tools/send_whatsapp",
{
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${adminToken}`,
},
body: JSON.stringify({
enabled: true,
config: { content_sid: "HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" },
}),
},
);
send_telegram¶
Sends a plain-text Telegram message. Unlike send_whatsapp there is no
template to get approved: a bot may message any chat that has already started
a conversation with it, in whatever wording the agent chooses. That makes it
the quickest outbound channel to set up.
Both config fields are optional and fall back to the deployment's own
TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID. Set them here only when an agent
needs its own bot or its own destination chat.
| Field | Type | Required | Falls back to | Notes |
|---|---|---|---|---|
bot_token |
string | No | TELEGRAM_BOT_TOKEN |
From @BotFather. Write-only, never read back. |
chat_id |
string | No | TELEGRAM_CHAT_ID |
A user, group, or channel id, e.g. -1001234567890. |
A message longer than Telegram's 4096-character limit is sent as several messages rather than truncated.
Telegram cannot place calls
The Telegram Bot API has no method for starting, receiving, or joining a
voice or video call, so there is no Telegram equivalent of
start_phone_call. sendVoice delivers a recorded audio file, not a
conversation. Use the phone channel for live audio.
start_phone_call¶
No config. Places an outbound phone call to a number the visitor just gave
the agent during a text or widget conversation, carries the recent chat
transcript forward as context, then continues that same agent's persona
over the new phone session. Requires the agent to have its own
twilio_phone_number configured; has no effect if the conversation is
already a phone call. Limited to one triggered call per chat session (see
Call.triggered_by_call_id), so a single conversation can't dial
repeatedly. Pair it with transfer_to_human (enabled on the same agent)
to finish a chat-to-call-to-human handoff: once the phone leg connects,
the agent can warm-transfer it to a real person exactly as it would on
any other phone call.
transfer_to_human¶
config.transfer_number (string, required by this tool's own
config_schema): the E.164 phone number dialed in to take over the call.
Only takes effect on phone calls; has no effect in a widget session, which
has no phone leg to transfer.
On a deployment licensed for the taskrouter feature, three optional
config fields, taskrouter_workspace_sid, taskrouter_workflow_sid, and
taskrouter_task_attributes (a JSON string the Workflow routes on, e.g.
{"skill": "billing"}), route the handoff through a Twilio TaskRouter
Workspace: the transfer dials whichever Worker TaskRouter assigns, and
falls back to transfer_number if none is assigned within a few seconds.
Built-in tool catalog¶
Most of these are licensed: a tool the licence does not cover is never
registered at all, so the model is not aware of it rather than being told
it may not use it. Six are always registered on every plan, including the
free tier: record_summary, capture_contact_info, end_call,
search_skills, verify_staff_member, and verify_caller_identity.
search_knowledge_base needs the rag right, which every current plan
grants. GET /api/v1/agents/{agent_id}/tools returns exactly what this
deployment has, which is more reliable than reading this table.
| Tool | Category | Config required | Description |
|---|---|---|---|
record_summary |
built_in |
None | Writes a summary of the conversation once it's wrapping up. |
capture_contact_info |
built_in |
None | Records the caller or visitor's name and/or email as it learns them. |
verify_staff_member |
built_in |
None | Confirms a self-reported staff claim against a code from the staff roster. With an empty roster it refuses every claim. |
verify_caller_identity |
built_in |
verify_service_sid (string, required) |
Sends a one-time passcode to the caller's number or email and checks it, live proof of control. Needs a Twilio Verify Service. |
send_webhook |
custom |
url (string, required) |
Sends arbitrary JSON to an external endpoint, notify a CRM, create a ticket, or trigger any integration outside AiFlow. |
search_knowledge_base |
knowledge |
None | Searches this agent's active, indexed context documents for a relevant passage. |
search_skills |
knowledge |
None | Looks up a step-by-step procedure matching the current situation, distinct from a fact lookup. |
send_telegram |
messaging |
bot_token, chat_id (both optional) |
Sends a plain-text Telegram message. No template approval, unlike WhatsApp. |
send_whatsapp |
messaging |
content_sid (string, required) |
Sends the caller a WhatsApp message using a pre-approved Content Template. |
send_email |
messaging |
from_address (string, optional) |
Sends the caller or visitor an email. The agent writes styled HTML content, rendered inside this deployment's own branded template automatically (Settings → Branding, falling back to AiFlow's own identity if unset), with a plain-text fallback part generated alongside it. from_address overrides the platform default sender for this agent only; omit it to use the deployment default. |
reply_to_email |
messaging |
None | Same automatic HTML and branded formatting as send_email, but replies to an inbound email through this agent's own connected mailbox address rather than send_email's platform-wide sender. See Mailbox connections. |
start_phone_call |
built_in |
None | Places an outbound call to a number given during a chat/widget session, carrying the transcript forward. Once per session; requires twilio_phone_number. |
transfer_to_human |
built_in |
transfer_number (string, required) |
Hands a live phone call to a real person, with a brief spoken summary first. Phone calls only. Optional taskrouter_workspace_sid / taskrouter_workflow_sid / taskrouter_task_attributes route the handoff through Twilio TaskRouter (licensed taskrouter feature) instead of the fixed number. |
delegate_to_agent |
orchestration |
None | Hands a narrowly-scoped task to another configured agent and relays its one-shot text answer. Requires a delegation link to the target agent. |
delegate_to_orchestrator |
orchestration |
None | Hands a task to a configured Orchestrator and relays its answer. Only present in the catalog when Orchestrators are enabled for this deployment. |
end_call |
built_in |
None | Ends the conversation once it's genuinely finished. |
crm_upsert_contact |
custom |
provider (string, required) |
Creates or updates a contact in the connected CRM. See CRM connectors. |
crm_create_ticket |
custom |
provider (string, required) |
Creates a support ticket or case in the connected CRM/helpdesk. See CRM connectors. |
crm_log_call_activity |
custom |
provider (string, required) |
Logs this call against the caller's contact in the connected CRM/helpdesk. See CRM connectors. |
follow_up |
automation |
frequency_days (integer), reason (string), both required |
Periodically scans the Contacts list and reaches out again by email or call when one still needs a follow-up. See the note below. |
follow_up runs on a schedule, not mid-conversation
Every other tool on this page is a function the model calls during a
live conversation. follow_up instead runs on its own timer, every
frequency_days days: it scans every contact who has talked to this
agent, asks the model whether their situation still matches reason
(free text you set, e.g. "they showed interest in a product but
something seemed to block them from buying"), and for anyone it
is, sends an email or places a call, whichever the model judges
fits, subject to that contact having an email or phone number on
file. Two contacts talking to the same agent at different times
become due at different times; a contact is never followed up with
again sooner than frequency_days after their last one, tracked on
their own Contacts record. This tool is also available on
Orchestrators (see Orchestrator tools),
where a sweep covers the whole shared Contacts list instead of one
agent's own contacts, and only email is offered: an Orchestrator has
no outbound-calling capability the way an agent does.
Next¶
- Custom tools: back a new tool with any HTTP endpoint you control.
- MCP servers: connect an agent to an external Model Context Protocol server instead.
- CRM connectors: the OAuth connection the three
crm_*tools above act through. - Agent-to-agent delegation: the admin-configured link
delegate_to_agentactually depends on.