Tools
Create native tool
Add one of Verbeo’s built-in tools to an assistant: end_call to hang up, transfer_call to hand the call to a person, send_sms to text the caller. It is switched on in the assistant’s nativeTools in the same request.
POST
/
tool
/
native
Create native tool
curl --request POST \
--url https://api.verbeo.ai/v1/tool/native \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_id": "<string>",
"tool_name": "<string>",
"description": {},
"transfer_call_mode": "<string>",
"transfer_call_destination": {},
"transfer_call_type": "<string>",
"sms_content_type": "<string>",
"sms_static_message": {},
"twilio_account_sid": {},
"twilio_auth_token": {},
"twilio_from_number": {},
"timeout_seconds": 123
}
'import requests
url = "https://api.verbeo.ai/v1/tool/native"
payload = {
"agent_id": "<string>",
"tool_name": "<string>",
"description": {},
"transfer_call_mode": "<string>",
"transfer_call_destination": {},
"transfer_call_type": "<string>",
"sms_content_type": "<string>",
"sms_static_message": {},
"twilio_account_sid": {},
"twilio_auth_token": {},
"twilio_from_number": {},
"timeout_seconds": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_id: '<string>',
tool_name: '<string>',
description: {},
transfer_call_mode: '<string>',
transfer_call_destination: {},
transfer_call_type: '<string>',
sms_content_type: '<string>',
sms_static_message: {},
twilio_account_sid: {},
twilio_auth_token: {},
twilio_from_number: {},
timeout_seconds: 123
})
};
fetch('https://api.verbeo.ai/v1/tool/native', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.verbeo.ai/v1/tool/native",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'agent_id' => '<string>',
'tool_name' => '<string>',
'description' => [
],
'transfer_call_mode' => '<string>',
'transfer_call_destination' => [
],
'transfer_call_type' => '<string>',
'sms_content_type' => '<string>',
'sms_static_message' => [
],
'twilio_account_sid' => [
],
'twilio_auth_token' => [
],
'twilio_from_number' => [
],
'timeout_seconds' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.verbeo.ai/v1/tool/native"
payload := strings.NewReader("{\n \"agent_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"description\": {},\n \"transfer_call_mode\": \"<string>\",\n \"transfer_call_destination\": {},\n \"transfer_call_type\": \"<string>\",\n \"sms_content_type\": \"<string>\",\n \"sms_static_message\": {},\n \"twilio_account_sid\": {},\n \"twilio_auth_token\": {},\n \"twilio_from_number\": {},\n \"timeout_seconds\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.verbeo.ai/v1/tool/native")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"description\": {},\n \"transfer_call_mode\": \"<string>\",\n \"transfer_call_destination\": {},\n \"transfer_call_type\": \"<string>\",\n \"sms_content_type\": \"<string>\",\n \"sms_static_message\": {},\n \"twilio_account_sid\": {},\n \"twilio_auth_token\": {},\n \"twilio_from_number\": {},\n \"timeout_seconds\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.verbeo.ai/v1/tool/native")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"agent_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"description\": {},\n \"transfer_call_mode\": \"<string>\",\n \"transfer_call_destination\": {},\n \"transfer_call_type\": \"<string>\",\n \"sms_content_type\": \"<string>\",\n \"sms_static_message\": {},\n \"twilio_account_sid\": {},\n \"twilio_auth_token\": {},\n \"twilio_from_number\": {},\n \"timeout_seconds\": 123\n}"
response = http.request(request)
puts response.read_bodyAdds a native tool to an assistant, appends its id to the assistant’s
config.toolIds and switches it on in config.nativeTools, with the same settings. Verbeo runs a native tool itself, so its endpoint, method, headers and argument schema are set for you: you send only its own settings.
An assistant has at most one native tool of each name. A new assistant already has end_call unless it was created with nativeTools.end_call.enabled: false. To change a native tool that exists, find it with List tools and is_native: true, then use Update native tool.
Body
string
required
UUID of the assistant the tool belongs to.
string
required
Which tool:
end_call, send_sms or transfer_call. The rest of the body is that tool’s settings, below; anything else is ignored.Every native tool
string | null
What the model is told about the tool: when to use it. Leave it out or blank and the default is written:
end_call:End the call when user has to leave (like says bye) or you are instructed to do so.transfer_call:Transfer the call to a human when the caller asks for one or the request cannot be handled.send_sms: empty.
transfer_call
string
default:"static"
static always dials transfer_call_destination. dynamic lets the assistant choose the number from the conversation: say in description how it should choose.string | null
The number a static transfer dials, in E.164 format:
+15551234567. Required when the mode is static.string
default:"cold"
cold or warm.The dashboard keeps a dynamic transfer’s guidance in
description, after a line that reads [DYNAMIC PROMPT]. The assistant’s nativeTools.transfer_call shows what comes before that line as description and what follows as dynamicPrompt.send_sms
string
default:"prompt"
prompt: the assistant writes the message. static: every SMS is sms_static_message.string | null
The text a static SMS sends. Required when
sms_content_type is static.string | null
The Twilio account to send from:
AC followed by 32 hexadecimal characters. Send it together with twilio_auth_token, or send neither, and Verbeo uses the Twilio account behind the call’s number. Responses show it as "********".string | null
That account’s auth token. Write-only: no response includes it.
string | null
The sender: a number in E.164 format (
+14155550123), or an alphanumeric sender ID of up to 11 letters, digits and spaces with at least one letter (Acme). Leave it out and Verbeo picks the sender, normally the number the call is on. It must be able to send SMS from the Twilio account that sends the message.number
default:"30"
The tool’s timeout: a whole number of seconds, from
5 to 300.What Verbeo sets
| Field | Value |
|---|---|
endpoint_url | native:// and the tool’s name |
http_method | POST |
headers | {} |
timeout_seconds | 30 for end_call and transfer_call |
parameters | From the settings: send_sms with prompt takes a message, and with static nothing; a static transfer_call takes a reason, a dynamic one a phone_number and a reason; end_call takes nothing |
Request
curl -X POST "https://api.verbeo.ai/v1/tool/native" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
"tool_name": "transfer_call",
"description": "Transfer to the billing team when the caller asks about an invoice.",
"transfer_call_mode": "static",
"transfer_call_destination": "+15551234567"
}'
const res = await fetch("https://api.verbeo.ai/v1/tool/native", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VERBEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
agent_id: "550e8400-e29b-41d4-a716-446655440000",
tool_name: "send_sms",
description: "Text the caller our address when they ask for it.",
sms_content_type: "prompt",
twilio_account_sid: process.env.TWILIO_ACCOUNT_SID,
twilio_auth_token: process.env.TWILIO_AUTH_TOKEN,
twilio_from_number: "+14155550123",
}),
});
const { data: tool } = await res.json();
import os, requests
tool = requests.post(
"https://api.verbeo.ai/v1/tool/native",
headers={"Authorization": f"Bearer {os.environ['VERBEO_API_KEY']}"},
json={
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
"tool_name": "transfer_call",
"description": "Transfer to the billing team when the caller asks about an invoice.",
"transfer_call_mode": "static",
"transfer_call_destination": "+15551234567",
},
).json()["data"]
Response
201 Created with the new tool object.
{
"success": true,
"data": {
"id": "5a7d1c3e-2b4f-4e6a-8c9d-0e1f2a3b4c5d",
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
"tool_name": "transfer_call",
"description": "Transfer to the billing team when the caller asks about an invoice.",
"endpoint_url": "native://transfer_call",
"http_method": "POST",
"headers": {},
"parameters": {
"properties": {
"reason": { "type": "string", "description": "Brief reason why the user wants to be transferred" }
},
"required": ["reason"]
},
"timeout_seconds": 30,
"is_native": true,
"transfer_call_mode": "static",
"transfer_call_destination": "+15551234567",
"transfer_call_type": "cold",
"twilio_account_sid": null,
"created_at": "2026-01-15T10:30:00.123456+00:00",
"updated_at": "2026-01-15T10:30:00.123456+00:00",
"…": "the rest of the tool object"
}
}
Errors
| Code | Status | When |
|---|---|---|
VALIDATION_FAILED | 422 | A tool_name that is not a native tool’s (tool_name: must be end_call, send_sms or transfer_call); a static transfer with no destination (transfer_call_destination: required for a static transfer); a static SMS with no message (sms_static_message: required when sms_content_type is static); half a Twilio credential (twilio_auth_token: required when twilio_account_sid is set, or the reverse); a malformed twilio_account_sid or twilio_from_number; or "********" for a credential, since a new tool has no saved value for it to stand for. |
CONFLICT | 409 | The assistant already has this native tool: This agent already has a tool named "end_call". |
NOT_FOUND | 404 | No such assistant, or it belongs to another workspace: Agent not found. |
Was this page helpful?
⌘I
Create native tool
curl --request POST \
--url https://api.verbeo.ai/v1/tool/native \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_id": "<string>",
"tool_name": "<string>",
"description": {},
"transfer_call_mode": "<string>",
"transfer_call_destination": {},
"transfer_call_type": "<string>",
"sms_content_type": "<string>",
"sms_static_message": {},
"twilio_account_sid": {},
"twilio_auth_token": {},
"twilio_from_number": {},
"timeout_seconds": 123
}
'import requests
url = "https://api.verbeo.ai/v1/tool/native"
payload = {
"agent_id": "<string>",
"tool_name": "<string>",
"description": {},
"transfer_call_mode": "<string>",
"transfer_call_destination": {},
"transfer_call_type": "<string>",
"sms_content_type": "<string>",
"sms_static_message": {},
"twilio_account_sid": {},
"twilio_auth_token": {},
"twilio_from_number": {},
"timeout_seconds": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_id: '<string>',
tool_name: '<string>',
description: {},
transfer_call_mode: '<string>',
transfer_call_destination: {},
transfer_call_type: '<string>',
sms_content_type: '<string>',
sms_static_message: {},
twilio_account_sid: {},
twilio_auth_token: {},
twilio_from_number: {},
timeout_seconds: 123
})
};
fetch('https://api.verbeo.ai/v1/tool/native', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.verbeo.ai/v1/tool/native",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'agent_id' => '<string>',
'tool_name' => '<string>',
'description' => [
],
'transfer_call_mode' => '<string>',
'transfer_call_destination' => [
],
'transfer_call_type' => '<string>',
'sms_content_type' => '<string>',
'sms_static_message' => [
],
'twilio_account_sid' => [
],
'twilio_auth_token' => [
],
'twilio_from_number' => [
],
'timeout_seconds' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.verbeo.ai/v1/tool/native"
payload := strings.NewReader("{\n \"agent_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"description\": {},\n \"transfer_call_mode\": \"<string>\",\n \"transfer_call_destination\": {},\n \"transfer_call_type\": \"<string>\",\n \"sms_content_type\": \"<string>\",\n \"sms_static_message\": {},\n \"twilio_account_sid\": {},\n \"twilio_auth_token\": {},\n \"twilio_from_number\": {},\n \"timeout_seconds\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.verbeo.ai/v1/tool/native")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"description\": {},\n \"transfer_call_mode\": \"<string>\",\n \"transfer_call_destination\": {},\n \"transfer_call_type\": \"<string>\",\n \"sms_content_type\": \"<string>\",\n \"sms_static_message\": {},\n \"twilio_account_sid\": {},\n \"twilio_auth_token\": {},\n \"twilio_from_number\": {},\n \"timeout_seconds\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.verbeo.ai/v1/tool/native")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"agent_id\": \"<string>\",\n \"tool_name\": \"<string>\",\n \"description\": {},\n \"transfer_call_mode\": \"<string>\",\n \"transfer_call_destination\": {},\n \"transfer_call_type\": \"<string>\",\n \"sms_content_type\": \"<string>\",\n \"sms_static_message\": {},\n \"twilio_account_sid\": {},\n \"twilio_auth_token\": {},\n \"twilio_from_number\": {},\n \"timeout_seconds\": 123\n}"
response = http.request(request)
puts response.read_body