Agents
Patch Update to Voice AI Agent API
Learn how to partially update properties. Update Bolna Voice AI agent name, welcome message, webhook URL, voice settings, calling guardrails, telephony provider, and prompts, using this endpoint.
PATCH
/
v2
/
agent
/
{agent_id}
cURL
curl --request PATCH \
--url https://api.bolna.ai/v2/agent/{agent_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_config": {
"agent_name": "Alfred",
"agent_welcome_message": "How are you doing Bruce?",
"webhook_url": null,
"ingest_source_config": {
"source_type": "api",
"source_url": "https://example.com/api/data",
"source_auth_token": "abc123",
"source_name": "leads_sheet_june.csv"
},
"telephony_provider": "sip-trunk",
"calling_guardrails": {
"call_start_hour": 9,
"call_end_hour": 21
}
},
"agent_prompts": {}
}
'import requests
url = "https://api.bolna.ai/v2/agent/{agent_id}"
payload = {
"agent_config": {
"agent_name": "Alfred",
"agent_welcome_message": "How are you doing Bruce?",
"webhook_url": None,
"ingest_source_config": {
"source_type": "api",
"source_url": "https://example.com/api/data",
"source_auth_token": "abc123",
"source_name": "leads_sheet_june.csv"
},
"telephony_provider": "sip-trunk",
"calling_guardrails": {
"call_start_hour": 9,
"call_end_hour": 21
}
},
"agent_prompts": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_config: {
agent_name: 'Alfred',
agent_welcome_message: 'How are you doing Bruce?',
webhook_url: null,
ingest_source_config: {
source_type: 'api',
source_url: 'https://example.com/api/data',
source_auth_token: 'abc123',
source_name: 'leads_sheet_june.csv'
},
telephony_provider: 'sip-trunk',
calling_guardrails: {call_start_hour: 9, call_end_hour: 21}
},
agent_prompts: {}
})
};
fetch('https://api.bolna.ai/v2/agent/{agent_id}', 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.bolna.ai/v2/agent/{agent_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'agent_config' => [
'agent_name' => 'Alfred',
'agent_welcome_message' => 'How are you doing Bruce?',
'webhook_url' => null,
'ingest_source_config' => [
'source_type' => 'api',
'source_url' => 'https://example.com/api/data',
'source_auth_token' => 'abc123',
'source_name' => 'leads_sheet_june.csv'
],
'telephony_provider' => 'sip-trunk',
'calling_guardrails' => [
'call_start_hour' => 9,
'call_end_hour' => 21
]
],
'agent_prompts' => [
]
]),
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.bolna.ai/v2/agent/{agent_id}"
payload := strings.NewReader("{\n \"agent_config\": {\n \"agent_name\": \"Alfred\",\n \"agent_welcome_message\": \"How are you doing Bruce?\",\n \"webhook_url\": null,\n \"ingest_source_config\": {\n \"source_type\": \"api\",\n \"source_url\": \"https://example.com/api/data\",\n \"source_auth_token\": \"abc123\",\n \"source_name\": \"leads_sheet_june.csv\"\n },\n \"telephony_provider\": \"sip-trunk\",\n \"calling_guardrails\": {\n \"call_start_hour\": 9,\n \"call_end_hour\": 21\n }\n },\n \"agent_prompts\": {}\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.bolna.ai/v2/agent/{agent_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_config\": {\n \"agent_name\": \"Alfred\",\n \"agent_welcome_message\": \"How are you doing Bruce?\",\n \"webhook_url\": null,\n \"ingest_source_config\": {\n \"source_type\": \"api\",\n \"source_url\": \"https://example.com/api/data\",\n \"source_auth_token\": \"abc123\",\n \"source_name\": \"leads_sheet_june.csv\"\n },\n \"telephony_provider\": \"sip-trunk\",\n \"calling_guardrails\": {\n \"call_start_hour\": 9,\n \"call_end_hour\": 21\n }\n },\n \"agent_prompts\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.bolna.ai/v2/agent/{agent_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"agent_config\": {\n \"agent_name\": \"Alfred\",\n \"agent_welcome_message\": \"How are you doing Bruce?\",\n \"webhook_url\": null,\n \"ingest_source_config\": {\n \"source_type\": \"api\",\n \"source_url\": \"https://example.com/api/data\",\n \"source_auth_token\": \"abc123\",\n \"source_name\": \"leads_sheet_june.csv\"\n },\n \"telephony_provider\": \"sip-trunk\",\n \"calling_guardrails\": {\n \"call_start_hour\": 9,\n \"call_end_hour\": 21\n }\n },\n \"agent_prompts\": {}\n}"
response = http.request(request)
puts response.read_body{
"message": "success",
"state": "updated"
}{
"error": 123,
"message": "<string>"
}Partially update an existing agent. Unlike the full update (
You can also combine multiple attributes in a single request:
PUT), which replaces the entire agent configuration, PATCH only touches the attributes you include in the request body — everything else is left unchanged.
Returns HTTP 200 with { "message": "success", "state": "updated" }.
Use
PATCH for small, targeted edits (renaming an agent, swapping a voice, updating a webhook URL). Use PUT when you need to rewrite tasks, toolchains, or the full prompt structure.Updatable attributes
Only the following attributes can be updated viaPATCH. Any other field in the body is ignored.
| Attribute | Location | Description |
|---|---|---|
agent_name | agent_config | Display name of the agent. |
agent_welcome_message | agent_config | First message the agent speaks when a call connects. |
webhook_url | agent_config | URL that receives the execution payload as call status changes. Whitelist source IPs 13.203.39.153, 13.126.9.249 and 13.202.133.53. Pass null to remove it. |
synthesizer | agent_config | Text-to-speech configuration (provider, voice, model, etc.). |
ingest_source_config | agent_config | CRM ingestion source for inbound agents (api, csv, or google_sheet). |
telephony_provider | agent_config | Telephony provider. Changing it auto-updates the audio format. |
calling_guardrails | agent_config | Time-based restrictions for outbound calls. |
agent_prompts | top-level | Prompts per task, keyed as task_1, task_2, … |
All agent-config attributes go inside the
agent_config object. agent_prompts is a top-level key, a sibling of agent_config.calling_guardrails
Restrict when your agent places outbound calls. Calls triggered outside the allowed window are automatically rescheduled to the next allowed start time in the recipient’s timezone. It accepts two keys:| Key | Type | Description |
|---|---|---|
call_start_hour | integer (0–23) | Start of the allowed calling window, 24-hour format. |
call_end_hour | integer (0–23) | End of the allowed calling window, 24-hour format. Must be ≥ call_start_hour. |
Update calling guardrails
{
"agent_config": {
"calling_guardrails": {
"call_start_hour": 9,
"call_end_hour": 21
}
}
}
Hours use 24-hour format:
0 = midnight, 9 = 9 AM, 17 = 5 PM, 21 = 9 PM. See the Calling Guardrails guide for rescheduling behavior and regional calling regulations.telephony_provider
Switch the telephony provider the agent uses. When changed, the agent’s audio input/output format is updated automatically to match the provider (wav for twilio/plivo/exotel/vobiz, ulaw for sip-trunk).
Accepted values: twilio, plivo, exotel, vobiz, sip-trunk, default.
Switch to SIP trunk
{
"agent_config": {
"telephony_provider": "sip-trunk"
}
}
If you patch
telephony_provider to sip-trunk, the next step is to set the inbound agent so your SIP trunk phone number maps to this agent for receiving inbound calls.Examples
{
"agent_config": {
"agent_name": "Support Agent v2",
"agent_welcome_message": "Hi! Thanks for calling. How can I help?"
}
}
{
"agent_config": {
"webhook_url": "https://your-server.com/bolna-webhook"
}
}
{
"agent_config": {
"synthesizer": {
"provider": "elevenlabs",
"provider_config": {
"voice": "Nila",
"voice_id": "V9LCAAi4tTlqe9JadbCo",
"model": "eleven_turbo_v2_5"
},
"stream": true,
"buffer_size": 250,
"audio_format": "wav"
}
}
}
{
"agent_prompts": {
"task_1": {
"system_prompt": "You are a helpful support agent. Keep replies short."
}
}
}
Combined patch
{
"agent_config": {
"agent_name": "Sales Agent",
"webhook_url": "https://your-server.com/bolna-webhook",
"telephony_provider": "plivo",
"calling_guardrails": {
"call_start_hour": 9,
"call_end_hour": 21
}
},
"agent_prompts": {
"task_1": {
"system_prompt": "You are an outbound sales agent. Be concise and friendly."
}
}
}
200 Response
{
"message": "success",
"state": "updated"
}
Next steps
Full update (PUT)
Replace the entire agent configuration, tasks, and prompts.
Calling Guardrails
Control outbound call timing and rescheduling.
Set inbound agent
Map a phone number to an agent for inbound calls.
Webhooks
Receive call results without polling.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Body
application/json
Update an agent
Response
agent status response
Was this page helpful?
⌘I
cURL
curl --request PATCH \
--url https://api.bolna.ai/v2/agent/{agent_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_config": {
"agent_name": "Alfred",
"agent_welcome_message": "How are you doing Bruce?",
"webhook_url": null,
"ingest_source_config": {
"source_type": "api",
"source_url": "https://example.com/api/data",
"source_auth_token": "abc123",
"source_name": "leads_sheet_june.csv"
},
"telephony_provider": "sip-trunk",
"calling_guardrails": {
"call_start_hour": 9,
"call_end_hour": 21
}
},
"agent_prompts": {}
}
'import requests
url = "https://api.bolna.ai/v2/agent/{agent_id}"
payload = {
"agent_config": {
"agent_name": "Alfred",
"agent_welcome_message": "How are you doing Bruce?",
"webhook_url": None,
"ingest_source_config": {
"source_type": "api",
"source_url": "https://example.com/api/data",
"source_auth_token": "abc123",
"source_name": "leads_sheet_june.csv"
},
"telephony_provider": "sip-trunk",
"calling_guardrails": {
"call_start_hour": 9,
"call_end_hour": 21
}
},
"agent_prompts": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_config: {
agent_name: 'Alfred',
agent_welcome_message: 'How are you doing Bruce?',
webhook_url: null,
ingest_source_config: {
source_type: 'api',
source_url: 'https://example.com/api/data',
source_auth_token: 'abc123',
source_name: 'leads_sheet_june.csv'
},
telephony_provider: 'sip-trunk',
calling_guardrails: {call_start_hour: 9, call_end_hour: 21}
},
agent_prompts: {}
})
};
fetch('https://api.bolna.ai/v2/agent/{agent_id}', 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.bolna.ai/v2/agent/{agent_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'agent_config' => [
'agent_name' => 'Alfred',
'agent_welcome_message' => 'How are you doing Bruce?',
'webhook_url' => null,
'ingest_source_config' => [
'source_type' => 'api',
'source_url' => 'https://example.com/api/data',
'source_auth_token' => 'abc123',
'source_name' => 'leads_sheet_june.csv'
],
'telephony_provider' => 'sip-trunk',
'calling_guardrails' => [
'call_start_hour' => 9,
'call_end_hour' => 21
]
],
'agent_prompts' => [
]
]),
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.bolna.ai/v2/agent/{agent_id}"
payload := strings.NewReader("{\n \"agent_config\": {\n \"agent_name\": \"Alfred\",\n \"agent_welcome_message\": \"How are you doing Bruce?\",\n \"webhook_url\": null,\n \"ingest_source_config\": {\n \"source_type\": \"api\",\n \"source_url\": \"https://example.com/api/data\",\n \"source_auth_token\": \"abc123\",\n \"source_name\": \"leads_sheet_june.csv\"\n },\n \"telephony_provider\": \"sip-trunk\",\n \"calling_guardrails\": {\n \"call_start_hour\": 9,\n \"call_end_hour\": 21\n }\n },\n \"agent_prompts\": {}\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.bolna.ai/v2/agent/{agent_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_config\": {\n \"agent_name\": \"Alfred\",\n \"agent_welcome_message\": \"How are you doing Bruce?\",\n \"webhook_url\": null,\n \"ingest_source_config\": {\n \"source_type\": \"api\",\n \"source_url\": \"https://example.com/api/data\",\n \"source_auth_token\": \"abc123\",\n \"source_name\": \"leads_sheet_june.csv\"\n },\n \"telephony_provider\": \"sip-trunk\",\n \"calling_guardrails\": {\n \"call_start_hour\": 9,\n \"call_end_hour\": 21\n }\n },\n \"agent_prompts\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.bolna.ai/v2/agent/{agent_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"agent_config\": {\n \"agent_name\": \"Alfred\",\n \"agent_welcome_message\": \"How are you doing Bruce?\",\n \"webhook_url\": null,\n \"ingest_source_config\": {\n \"source_type\": \"api\",\n \"source_url\": \"https://example.com/api/data\",\n \"source_auth_token\": \"abc123\",\n \"source_name\": \"leads_sheet_june.csv\"\n },\n \"telephony_provider\": \"sip-trunk\",\n \"calling_guardrails\": {\n \"call_start_hour\": 9,\n \"call_end_hour\": 21\n }\n },\n \"agent_prompts\": {}\n}"
response = http.request(request)
puts response.read_body{
"message": "success",
"state": "updated"
}{
"error": 123,
"message": "<string>"
}
