Appearance
Outbound Calls
Outbound calls are calls your system initiates. You pass structured data alongside the call — the agent uses it to personalise the greeting, the LLM context, and pre-action tool calls.
Contents
- How It Works
- Defining Context Variables
- Making an Outbound Call
- Using Variables in Greetings
- Using Variables in Flow Nodes
- Using Variables in Tool Calls
- Example 1 — Collections Agent
- Example 2 — Appointment Reminder
- Example 3 — Lead Follow-Up
- Batch Outbound Calls
How It Works
POST /api/calls/outbound
{
"phone_number": "+919876543210",
"agent_name": "collections-agent",
"custom_parameters": {
"customer_name": "Ravi Kumar",
"invoice_amount": 4500
}
}
↓
Platform dials the number
↓
When answered → greeting plays with {{customer_name}} substituted
↓
LLM sees: "Call context: customer_name: Ravi Kumar, invoice_amount: 4500"
↓
Pre-call / pre-action tools also receive these values as argsDefining Context Variables
Define the schema on the agent so the platform knows what to expect:
bash
curl -X PATCH https://your-domain.com/api/agents/<agent_id> \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"context_variables": {
"customer_name": {
"type": "string",
"description": "Customer full name"
},
"invoice_id": {
"type": "string",
"description": "Invoice reference number"
},
"amount_due": {
"type": "number",
"description": "Outstanding amount in INR"
},
"due_date": {
"type": "string",
"description": "Payment due date (YYYY-MM-DD)"
}
}
}'Context variables are documentation/schema — you don't have to define them to use custom_parameters, but defining them is good practice and enables validation.
Making an Outbound Call
bash
curl -X POST https://your-domain.com/api/calls/outbound \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+919876543210",
"agent_name": "collections-agent",
"custom_parameters": {
"customer_name": "Ravi Kumar",
"invoice_id": "INV-7890",
"amount_due": 4500,
"due_date": "2026-03-25"
}
}'| Field | Required | Description |
|---|---|---|
phone_number | Yes | Number to dial, with country code |
agent_name | Yes | The name of the agent to use |
custom_parameters | No | Key-value pairs injected into the call |
Using Variables in Greetings
Use placeholders — substituted from custom_parameters before the greeting plays:
json
{
"greeting": "Hi {{customer_name}}, this is Priya calling from FinCare about invoice {{invoice_id}}."
}Becomes: "Hi Ravi Kumar, this is Priya calling from FinCare about invoice INV-7890."
Rules:
- Unknown variables are left as
— double-check spelling - Variables are case-sensitive:
≠ - Empty/missing variables render as an empty string
Using Variables in Flow Nodes
Variables are available in task_messages and role_messages via :
json
{
"role": "system",
"content": "You are calling {{customer_name}} about their overdue invoice {{invoice_id}} of {{amount_due}} rupees, originally due on {{due_date}}. Be polite but firm about arranging payment."
}This is substituted when the node is entered, so the LLM's prompt contains the actual values.
Using Variables in Tool Calls
Context variables are automatically merged into every tool call's args:
json
{
"phone_number": "+919876543210",
"direction": "outbound",
"customer_name": "Ravi Kumar",
"invoice_id": "INV-7890",
"amount_due": 4500,
"due_date": "2026-03-25"
}Your webhook receives all of them without any extra configuration. This means a pre-action on the initial node (like a CRM lookup) automatically gets the customer context you passed.
Example 1 — Collections Agent
Full outbound agent for collecting overdue loan payments.
json
{
"version": "1",
"agent": {
"name": "collections-agent",
"prompt": "You are Arjun, a polite but firm collections executive at FinCare. Your goal is to remind the customer of their overdue balance and arrange a payment commitment. Always be respectful. Never threaten or make guarantees about legal consequences.",
"greeting": "Hello, may I speak with {{customer_name}}?",
"context_variables": {
"customer_name": { "type": "string", "description": "Customer full name" },
"loan_id": { "type": "string", "description": "Loan account number" },
"amount_due": { "type": "number", "description": "Overdue amount in INR" },
"due_date": { "type": "string", "description": "Original due date (YYYY-MM-DD)" }
}
},
"tools": [
{
"id": "tool-record-promise",
"name": "record_payment_promise",
"description": "Record the customer's promise to pay by a specific date. Call this after the customer agrees to a payment date and amount.",
"webhook_url": "https://your-api.com/collections/promise",
"webhook_method": "POST",
"headers": { "Authorization": "Bearer your-secret" },
"parameters": {
"properties": {
"loan_id": { "type": "string" },
"payment_date": { "type": "string", "description": "Promised payment date (YYYY-MM-DD)" },
"amount": { "type": "number", "description": "Amount the customer agreed to pay" }
},
"required": ["loan_id", "payment_date", "amount"]
}
}
],
"flow_nodes": [
{
"node_key": "confirm_identity",
"position": 0,
"is_initial": true,
"is_terminal": false,
"role_messages": [
{ "role": "system", "content": "You are Arjun, a polite collections executive at FinCare." }
],
"task_messages": [
{ "role": "system", "content": "Confirm you are speaking with {{customer_name}}. If confirmed, call correct_person. If not {{customer_name}} or they are unavailable, call wrong_person." }
],
"functions": [
{ "name": "correct_person", "description": "Person confirmed they are {{customer_name}}", "next_node_key": "present_dues", "properties": {}, "required": [] },
{ "name": "wrong_person", "description": "Wrong person or they are unavailable", "next_node_key": "close_call", "properties": {}, "required": [] }
],
"tool_ids": [],
"builtin_tools": ["end_call"],
"pre_actions": [],
"position_xy": { "x": 100, "y": 200 }
},
{
"node_key": "present_dues",
"position": 1,
"is_initial": false,
"is_terminal": false,
"role_messages": [],
"task_messages": [
{
"role": "system",
"content": "Inform {{customer_name}} that their loan account {{loan_id}} has an overdue balance of {{amount_due}} rupees, originally due on {{due_date}}.\n\nAsk how they would like to resolve this. Offer:\n1. Pay the full amount now\n2. Partial payment today, rest by end of month\n3. Request a callback from a senior advisor\n\nIf they agree to pay on a specific date, call customer_agrees_to_pay.\nIf they want a callback, call customer_wants_callback.\nIf they dispute or refuse, call customer_disputes."
}
],
"functions": [
{
"name": "customer_agrees_to_pay",
"description": "Customer commits to paying on a specific date",
"next_node_key": "confirm_promise",
"properties": {
"payment_date": { "type": "string", "description": "Date they will pay (YYYY-MM-DD)" },
"amount": { "type": "number", "description": "Amount they agreed to pay" }
},
"required": ["payment_date", "amount"]
},
{
"name": "customer_wants_callback",
"description": "Customer wants a senior advisor to call back",
"next_node_key": "close_call",
"properties": {},
"required": []
},
{
"name": "customer_disputes",
"description": "Customer disputes the amount or refuses",
"next_node_key": "close_call",
"properties": {},
"required": []
}
],
"tool_ids": [],
"builtin_tools": ["end_call"],
"pre_actions": [],
"position_xy": { "x": 350, "y": 200 }
},
{
"node_key": "confirm_promise",
"position": 2,
"is_initial": false,
"is_terminal": false,
"role_messages": [],
"task_messages": [
{ "role": "system", "content": "Use the record_payment_promise tool to log the payment commitment. Include the loan_id from context, and the payment_date and amount the customer agreed to. Once recorded, read back the commitment to the customer and tell them they will receive a reminder. Then call commitment_recorded." }
],
"functions": [
{
"name": "commitment_recorded",
"description": "Payment promise has been recorded and confirmed to the customer",
"next_node_key": "close_call",
"properties": {},
"required": []
}
],
"tool_ids": ["tool-record-promise"],
"builtin_tools": ["end_call"],
"pre_actions": [],
"position_xy": { "x": 600, "y": 200 }
},
{
"node_key": "close_call",
"position": 3,
"is_initial": false,
"is_terminal": true,
"role_messages": [],
"task_messages": [
{ "role": "system", "content": "Thank the customer for their time. Wish them a good day. Then call end_call." }
],
"functions": [],
"tool_ids": [],
"builtin_tools": ["end_call"],
"pre_actions": [],
"position_xy": { "x": 850, "y": 200 }
}
]
}Trigger the call:
bash
curl -X POST https://your-domain.com/api/calls/outbound \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+919876543210",
"agent_name": "collections-agent",
"custom_parameters": {
"customer_name": "Ravi Kumar",
"loan_id": "LN-00456",
"amount_due": 8500,
"due_date": "2026-03-10"
}
}'Example 2 — Appointment Reminder
Freeform outbound agent that reminds patients about upcoming appointments.
json
{
"version": "1",
"agent": {
"name": "appointment-reminder",
"prompt": "You are a reminder bot for Dr. Sharma's clinic. Your only job is to remind the patient about their appointment and confirm whether they will attend.\n\nIf they confirm: note confirmation and end the call.\nIf they want to reschedule: ask for a preferred time and call schedule_reschedule.\nIf they want to cancel: call mark_cancelled and end politely.",
"greeting": "Hello {{patient_name}}, this is a reminder from Dr. Sharma's clinic. You have an appointment on {{appointment_date}} at {{appointment_time}}. Are you able to make it?",
"context_variables": {
"patient_name": { "type": "string", "description": "Patient's name" },
"appointment_date": { "type": "string", "description": "Date of appointment (e.g. March 21st)" },
"appointment_time": { "type": "string", "description": "Time of appointment (e.g. 10:30 AM)" },
"appointment_id": { "type": "string", "description": "Internal appointment reference" }
},
"tool_ids": ["<schedule_reschedule_uuid>", "<mark_cancelled_uuid>"]
},
"tools": [],
"flow_nodes": []
}Trigger:
bash
curl -X POST https://your-domain.com/api/calls/outbound \
-H "Authorization: Bearer <token>" \
-d '{
"phone_number": "+919876543210",
"agent_name": "appointment-reminder",
"custom_parameters": {
"patient_name": "Meera Iyer",
"appointment_date": "March 21st",
"appointment_time": "10:30 AM",
"appointment_id": "APT-2891"
}
}'Example 3 — Lead Follow-Up
Freeform outbound agent that follows up with prospects who submitted a contact form.
json
{
"version": "1",
"agent": {
"name": "lead-followup",
"prompt": "You are Aisha from HomeNest Realty. You are calling {{lead_name}} who recently enquired about properties in {{area}} with a budget of {{budget}}.\n\nYour goals:\n1. Confirm their interest is still active\n2. Understand their timeline and requirements better\n3. If interested, book a site visit using schedule_site_visit\n4. If not interested, log the outcome with log_lead_outcome\n\nBe warm and consultative. Do not push if they are not interested.",
"greeting": "Hello {{lead_name}}! This is Aisha from HomeNest Realty. You recently enquired about properties in {{area}} — I'm calling to help you find the perfect home. Is now a good time?",
"context_variables": {
"lead_name": { "type": "string", "description": "Lead's name" },
"area": { "type": "string", "description": "Area they enquired about" },
"budget": { "type": "string", "description": "Budget range mentioned in form" },
"lead_id": { "type": "string", "description": "CRM lead ID" }
},
"tool_ids": ["<schedule_site_visit_uuid>", "<log_lead_outcome_uuid>"]
},
"tools": [],
"flow_nodes": []
}Batch Outbound Calls
To make multiple outbound calls (e.g. from a list), loop over your records and call POST /api/calls/outbound for each. There is no batch endpoint — this is intentional to allow per-call control.
Example (shell loop):
bash
while IFS=',' read -r phone name loan_id amount due_date; do
curl -s -X POST https://your-domain.com/api/calls/outbound \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{
\"phone_number\": \"$phone\",
\"agent_name\": \"collections-agent\",
\"custom_parameters\": {
\"customer_name\": \"$name\",
\"loan_id\": \"$loan_id\",
\"amount_due\": $amount,
\"due_date\": \"$due_date\"
}
}"
sleep 1
done < contacts.csvExample (Python):
python
import httpx, csv
TOKEN = "your-token"
API = "https://your-domain.com/api/calls/outbound"
with open("contacts.csv") as f:
for row in csv.DictReader(f):
httpx.post(API, headers={"Authorization": f"Bearer {TOKEN}"}, json={
"phone_number": row["phone"],
"agent_name": "collections-agent",
"custom_parameters": {
"customer_name": row["name"],
"loan_id": row["loan_id"],
"amount_due": float(row["amount"]),
"due_date": row["due_date"],
}
})Add rate limiting appropriate for your telephony provider's concurrent call limits.