Creating a Voice Agent
This document provides a comprehensive guide for developers using the Partner API to create voice agents for inbound and outbound phone calls. It covers all prerequisites, endpoints, and the complete workflow from setup to agent creation.
-
-
-
Step 1: Set Up Google Calendar Integration (Optional)
-
Endpoint:
POST /v1/businesses/:businessId/integrations/google-calendar
-
-
Step 3: Upload Files for Knowledge Base (Optional)
-
Endpoint:
POST /v1/businesses/:businessId/files
-
-
-
Endpoint:
GET /v1/voices
-
-
Step 5: Create the Voice Agent
-
Endpoint:
POST /v1/businesses/:businessId/voice-agents
-
-
Step 6: Deploy the Voice Agent
-
Endpoint:
POST /v1/businesses/:businessId/voice-agents/:voiceAgentId/deploy
-
-
-
Endpoint:
POST /v1/businesses/:businessId/voice-agents/:voiceAgentId/call
-
Overview
A voice agent in the Partner API is a conversational AI that can handle phone calls. Creating and activating one involves:
-
Prerequisites: Business ID, optional integrations (Google Calendar)
-
Tools: Transfer tools, Google Calendar scheduling tools, or custom API tools
-
Knowledge Base: Optional files for RAG (Retrieval-Augmented Generation)
-
Voice Selection: Choose from available voices
-
Agent Creation: Define the agent with workflow or prose, activated hours, and configuration
-
Deployment: Deploy the agent to provision a phone number and make it live
The nexus for agent creation is the endpoint
POST /v1/businesses/:businessId/voice-agents
. After creation, deploy the agent using
POST /v1/businesses/:businessId/voice-agents/:voiceAgentId/deploy
to provision a phone number and activate it.
Once deployed:
-
INBOUND agents can receive calls at the provisioned phone number
-
OUTBOUND agents can make calls programmatically via the API
Prerequisites
Before creating a phone agent, ensure you have:
-
Partner API Access: Valid API credentials with appropriate scopes (
/v1/oauth/tokenendpoint) -
Business ID: A business entity that belongs to your organization
-
Required Scopes:
-
voice-agents:create,voice-agents:read,voice-agents:update,voice-agents:delete- For creating, reading, updating, and deleting agents -
tools:read,tools:create,tools:update,tools:delete- For managing tools -
files:read,files:create,files:delete- For knowledge base files -
voices:read- For selecting voices -
integrations:read,integrations:create,integrations:update,integrations:delete- For Google Calendar (if needed) -
calls:read- For viewing call history
-
Step-by-Step Guide
Step 1: Set Up Google Calendar Integration (Optional)
If you want your agent to schedule appointments in a Google Calendar, you must set up Google Calendar integration first.
Endpoint: POST /v1/businesses/:businessId/integrations/google-calendar
Request Body:
{
"accessToken": "ya29.a0AfH6SMC...", // Google OAuth access token
"calendarId": "primary" // Google Calendar ID (or specific calendar ID)
}
Response:
{
"id": "config-id-123",
"calendarId": "primary",
"aclRuleId": "acl-rule-id-456"
}
What Happens:
-
The system shares the specified Google Calendar with a service account
-
Creates or updates a
BusinessIntegrationConfigrecord -
Returns
calendarIdandaclRuleIdneeded for Google Calendar tools
Important Notes:
-
The
accessTokenmust have thehttps://www.googleapis.com/auth/calendarscope -
The calendar must be successfully shared with the service account
-
This integration is required before creating Google Calendar tools
Example:
curl -X POST \
https://api.example.com/partner-api/v1/businesses/biz_123/integrations/google-calendar \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accessToken": "ya29.a0AfH6SMC...",
"calendarId": "primary"
}'
Verify Integration:
GET /v1/businesses/:businessId/integrations/google-calendar
Returns the same structure if configured, or 404 if not set up.
Step 2: Create Tools
Tools enable your agent to perform actions like transferring calls or scheduling appointments. Tools are created as instances from templates.
2.1: List Available Tool Templates from the Tool Library
Endpoint:
GET /v1/tools
Response:
{
"items": [
{
"id": "template-transfer-001",
"isTemplate": true,
"name": "transferCall",
"displayName": "Transfer Call",
"type": "transferCall",
"config": { /* template config */ },
"configSchema": { /* JSON schema for configOverride */ }
},
{
"id": "template-googlecal-001",
"isTemplate": true,
"name": "googleCal",
"displayName": "Google Calendar",
"type": "apiRequest",
"config": { /* template config */ },
"configSchema": { /* JSON schema for configOverride */ }
}
],
"page": 1,
"page_size": 10,
"total": 2
}
2.2: Create a Transfer Call Tool
A transfer call tool is used to transfer a call to a destination. The configuration options are:
-
Destinations: An array of destination objects. Each destination object has the following properties:
-
name: The name of the destination.
-
phoneNumber: The phone number of the destination.
-
description: The description of the destination.
-
warmTransferEnabled: Whether to verify availability before connecting to the destination.
-
-
Custom on hold audio: An optional audio URL to play while on hold. If not provided, the default on hold audio will be used.
-
This is specified in the
messagesarray.-
type: "request-complete"
-
content: The URL of the audio file to play while on hold.
-
-
Endpoint:
POST /v1/businesses/:businessId/tools
Request Body:
{
"templateToolId": "template-transfer-001",
"configOverride": {
"destinations": [
{
"name": "Sales Team",
"phoneNumber": "+15551234567",
"description": "Main sales line",
"warmTransferEnabled": true
},
{
"name": "Support",
"phoneNumber": "+15559876543",
"description": "Customer support",
"warmTransferEnabled": false
}
],
"messages": [
{
"type": "request-complete",
"content": "https://example.com/audio/on-hold.mp3"
}
]
}
}
Response:
{
"id": "tool-instance-123",
"isTemplate": false,
"templateToolId": "template-transfer-001",
"name": "transferCall",
"displayName": "Transfer Call",
"type": "transferCall",
"config": { /* base template config */ },
"configOverride": { /* your overrides */ },
"effectiveConfig": { /* merged config */ },
"message": "Let me transfer you to our team...",
"businessId": "biz_123",
"enabled": true,
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-15T10:00:00Z"
}
Validation Rules:
-
Phone numbers must be in E.164 format:
+1XXXXXXXXXX(US only) -
Area code and exchange code cannot start with 0 or 1
-
At least one destination is required
-
messagesarray is optional (for on-hold audio)
What Happens:
-
Creates
TransferDestinationrecords in the database -
Stores
destinationIdsin the tool'sconfigOverride -
Returns the tool instance ID (use this in
toolIdswhen creating the agent)
Important: Save the returned
id
field (not
name
) for use in
toolIds
array. The
name
field is for your internal reference only.
2.3: Create a Google Calendar Tool
A Google Calendar tool is used to schedule appointments, search for appointments, and cancel appointments in a Google Calendar. The configuration options are:
-
Appointment config (optional): An object with the following properties:
-
slotDurationMinutes: The duration of each appointment slot in minutes. (default: 60)
-
slotBufferMinutes: The buffer time before and after each appointment slot in minutes. (default: 0)
-
advanceNoticeMinutes: The minimum number of minutes before the appointment time to allow for booking. (default: 1440)
-
hoursJson: Specify when appointments are available for booking with an object with the following properties: (defaults to business hours)
-
day of week mapped to an array of objects with the following properties:
-
openTime: The opening time of the day in HH:MM format.
-
closeTime: The closing time of the day in HH:MM format.
-
-
-
Prerequisite: Google Calendar integration must be set up (Step 1).
Endpoint:
POST /v1/businesses/:businessId/tools
Request Body:
{
"templateToolId": "template-googlecal-001",
"configOverride": {
"appointmentConfig": {
"slotDurationMinutes": 60,
"slotBufferMinutes": 15,
"advanceNoticeMinutes": 1440,
"hoursJson": {
"monday": [
{ "openTime": "09:00", "closeTime": "17:00" }
],
"tuesday": [
{ "openTime": "09:00", "closeTime": "17:00" }
],
"wednesday": [
{ "openTime": "09:00", "closeTime": "17:00" }
],
"thursday": [
{ "openTime": "09:00", "closeTime": "17:00" }
],
"friday": [
{ "openTime": "09:00", "closeTime": "17:00" }
]
}
}
}
}
Response:
{
"id": "tool-instance-456",
"isTemplate": false,
"templateToolId": "template-googlecal-001",
"name": "googleCal",
"displayName": "Google Calendar",
"type": "apiRequest",
"config": { /* base template config */ },
"configOverride": {
"appointmentConfigId": "appt-config-789"
},
"effectiveConfig": { /* merged config */ },
"businessId": "biz_123",
"enabled": true,
"createdAt": "2024-01-15T10:05:00Z",
"updatedAt": "2024-01-15T10:05:00Z"
}
Validation Rules:
-
slotDurationMinutes: 10-300 (default: 60) -
slotBufferMinutes: 0-120 (default: 0) -
advanceNoticeMinutes: 0-14400 (default: 1440 = 24 hours) -
hoursJson: Optional, maps day names to arrays of{openTime, closeTime}
What Happens:
-
Validates Google Calendar integration exists for the business
-
Creates or updates an
AppointmentConfigrecord -
Stores
appointmentConfigIdin the tool'sconfigOverride -
The scheduling URL is constructed server-side from
businessIdwhen building the voice assistant
Important: Save the returned
id
field (not
name
) for use in
toolIds
array. The
name
field is auto-generated for internal reference only.
Note: The Google Calendar tool actually three tools in the platform:
-
scheduleAppointment- Book an appointment -
searchAppointments- Search available slots -
cancelAppointment- Cancel an appointment
All three are automatically added when you include the Google Calendar tool instance ID in
toolIds
.
2.3.1: Google Calendar Tools Details
The Google Calendar tool is a multi-tool - one tool instance creates three distinct tools in the platform. An agent that can schedule appointments can also look up and confirm existing appointments, cancel existing appointments (and therefore "reschedule" appointments by canceling and rebooking).
The Three Tools:
-
scheduleAppointment- Books new appointments-
Used when the caller wants to book a time slot
-
Agent will search for available slots and book the appointment
-
Example: "I'd like to schedule an appointment for next Tuesday"
-
-
searchAppointments- Searches available time slots-
Used to find existing appointments (uses fuzzy search on fields like phone number, customer name, and address to find the appointment)
-
Example: "Can you remind me of my appointment on Friday?"
-
-
cancelAppointment- Cancels existing appointments-
Used to cancel appointments that have already been booked
-
Example: "I need to cancel my appointment on Friday"
-
In addition to these three abilities, behind the scenes the integration will be used to provide the agent with a list of available times slots, when a call is initiated.
How They Work Together:
When you create a Google Calendar tool instance and include it in
toolIds
, all three tools become available to the agent. The agent will automatically use the appropriate tool based on the conversation:
-
If caller wants to book → uses
scheduleAppointment(in combination with the available times slots) -
If caller asks about an existing appointment → uses
searchAppointments -
If caller wants to cancel → uses
searchAppointments, thencancelAppointment -
If caller wants to reschedule → uses
searchAppointments, thencancelAppointmentthenscheduleAppointment
Troubleshooting Google Calendar Tools:
-
"Google Calendar integration not configured"
-
Ensure you've set up the integration first (Step 1)
-
Verify with
GET /v1/businesses/:businessId/integrations/google-calendar
-
-
"Appointment booking fails"
-
Check that
appointmentConfighas valid hours -
Verify
slotDurationMinutesis reasonable (10-300) -
Ensure
advanceNoticeMinutesallows bookings for desired timeframes
-
-
"No available slots found"
-
Check
hoursJsonconfiguration -
Ensure calendar actually has free time slots
-
2.4: List Your Business Tools
Endpoint:
GET /v1/businesses/:businessId/tools
Returns all tool instances (not templates) for the business. Use the returned IDs in
toolIds
when creating the agent. Always use tool IDs (not names) in the
toolIds
array when creating agents
Understanding Default Tools
When you create a voice agent, certain tools are automatically added even if you don't specify them in
toolIds
:
-
endCalltool is always present - you cannot disable it -
a default
transferCalltool is added if the business has a phone number configured. If you provide a custom transfer tool, the default is not added. -
knowledgeBaseQuerytool is automatically created when you provideknowledgeBaseDocumentIds
Example Response:
{
"toolIds": [
"tool-instance-456", // Your custom Google Calendar tool
"auto-knowledge-base-tool", // Auto-created from knowledgeBaseDocumentIds
"auto-end-call-tool", // Always auto-added
"auto-transfer-tool" // Auto-added (if no custom transfer provided)
]
}
Tool Library Reference
The following table shows all available tool types in the Partner API (these have
isTemplate: true
in the response):
|
Tool Type |
Template Name |
Purpose |
Requires Config? |
Auto-Added? |
|---|---|---|---|---|
|
|
|
Transfer calls to destinations |
Yes (destinations) |
Conditional |
|
|
|
Schedule/search/cancel appointments |
Yes (Google Calendar integration) |
No |
|
|
|
End calls |
No |
Always |
|
|
N/A |
Query knowledge base |
Auto-created from files |
Conditional |
|
|
|
Custom function calls |
Yes (server URL, function name) |
No |
|
|
|
Generic API requests |
Yes (URL, method) |
No |
These tool templates are then configured for use with agents in the relevant business.
Notes:
-
Tool templates are read-only and define the base configuration
-
Tool instances are created from templates with business-specific overrides
-
Use tool instance IDs (not template IDs) in
toolIdswhen creating agents
Step 3: Upload Files for Knowledge Base (Optional)
Files are uploaded to a vector store for use in a knowledge base that an agent can query during conversations.
Endpoint: POST /v1/businesses/:businessId/files
Request:
multipart/form-data
Form Fields:
-
file: The file to upload (PDF, TXT, DOCX, etc.)
Response:
{
"id": "file-123",
"name": "product-catalog.pdf",
"mimeType": "application/pdf",
"sizeBytes": 1048576,
"businessId": "biz_123",
"status": "processing",
"createdAt": "2024-01-15T10:10:00Z",
"updatedAt": "2024-01-15T10:10:00Z"
}
Note: The
name
field in the response corresponds to the file's
displayName
in the database.
Status Values:
-
"processing"- File is being processed -
"ready"- File is ready to use (both vector store processing completed) -
"failed"- File processing failed
What Happens:
-
File is uploaded to the vector store
-
Record is added to the business's file table
-
Status is tracked (
"processing"→"ready")
Supported Formats:
-
PDF, TXT, DOCX, MD, and other text-based formats
Important Notes:
-
Files are processed asynchronously; status may be
"processing"initially -
Use the returned
idinknowledgeBaseDocumentIdswhen creating the agent
N.B. Providing
knowledgeBaseDocumentIds
automatically creates a knowledge base query tool. This tool is added to the agent's
toolIds
in the response, but the tool ID is not predictable before agent creation. Ensure files have
status: "ready"
before using them in agent creation.
Monitoring File Processing
Files are processed asynchronously after upload. You can check the file status before using files in agent creation.
Check File Status:
Endpoint:
GET /v1/businesses/:businessId/files/:fileId
Response:
{
"id": "file-123",
"name": "product-catalog.pdf",
"mimeType": "application/pdf",
"sizeBytes": 1048576,
"businessId": "biz_123",
"status": "processing", // <---or "ready" or "failed"
"createdAt": "2024-01-15T10:10:00Z",
"updatedAt": "2024-01-15T10:15:00Z"
}
Note: The
name
field in the response corresponds to the file's
displayName
in the database.
Status Values:
-
"processing"- File is being processed -
"ready"- File is ready to use (processing completed) -
"failed"- File processing failed
Important: Files must have
status: "ready"
before they can be used in agent creation.
Polling or Webhooks: You can poll the file status or use webhooks to be notified when the file is ready.
Step 4: Select a Voice
Voices are available from a curated collection. List available voices and select one by ID.
Endpoint: GET /v1/voices
Response:
[
{
"id": "voice-abc123",
"name": "Sarah",
"category": "conversational",
"description": "Friendly and professional",
"previewUrl": "https://..."
},
{
"id": "voice-def456",
"name": "Michael",
"category": "narrative",
"description": "Clear and authoritative",
"previewUrl": "https://..."
}
]
Get Specific Voice:
GET /v1/voices/:voiceId
Usage:
-
Use the
idin thevoiceIdfield when creating the agent -
If omitted, a default voice is used
-
Voices are read-only (managed by the platform)
-
Voices can be sampled using the
previewUrlfield
Step 5: Create the Voice Agent
This is the most complex endpoint. It combines all the above components into a working phone agent.
Endpoint: POST /v1/businesses/:businessId/voice-agents
Note: The
businessId
is provided as a path parameter in the URL, not in the request body.
Request Body Structure
{
// Required
name: string; // Agent name (1-40 chars)
type: "INBOUND" | "OUTBOUND"; // Agent type
// Workflow Definition (one of these required)
conversationFlow?: string; // Prose description of conversation
workflow?: { // OR structured workflow graph
nodes: Array<{
id: string;
type: "conversation" | "tool";
prompt: string;
firstMessage?: string;
label?: string;
}>;
edges: Array<{
from: string;
to: string;
when: string;
}>;
startNode: string;
};
// Optional Configuration
customInstructions?: string; // Additional special instructions for the agent
voiceId?: string; // From Step 4
toolIds?: string[]; // From Step 2
knowledgeBaseDocumentIds?: string[]; // From Step 3
// Personality
personality?: {
tone?: string; // e.g. "friendly", "professional"
style?: string; // e.g. "conversational", "narrative"
description?: string; // e.g. "A friendly and professional agent"
useEmpathy?: boolean; // e.g. true
useHumor?: boolean; // e.g. false
};
// Messages
firstMessage?: string; // Initial greeting (optional)
// Features
multilingual?: boolean; // only enable if you genuinely need to support multiple languages
backgroundSound?: string; // 'office' for the default office sound, or a custom sound URL
collectFields?: string[]; // What structured data to collect from the call (e.g., ["name", "phone", "email", "favorite_color"])
// Activated Hours (INBOUND only)
activatedHours?: {
timezone: string; // IANA timezone (e.g., "America/New_York") - this is the timezone of the business
hours: Array<{
day: string; // "monday", "tuesday", etc.
startTime: string; // "HH:MM" or "CLOSED" - the start time of the day
endTime: string; // "HH:MM" or "CLOSED" - the end time of the day
}>;
};
}
Workflow vs. Conversation Flow
You must provide either
workflow
or
conversationFlow
(not both). No matter what you provide the other will be created automatically. If both are provided,
workflow
takes precedence. Unless you are developing a workflow editor UI (e.g. using react-flow), it is recommended that you use the conversation flow option.
Option 1: Conversation Flow (Prose) - this is a description of the conversation flow in natural language
{
"conversationFlow": "Greet the caller warmly. Ask for their name and reason for calling. If they want to schedule, use the scheduling tool. If they need support, transfer to support."
}
Option 2: Workflow Graph (Structured) - this is a structured graph of the conversation flow
{
"workflow": {
"nodes": [
{
"id": "start",
"type": "conversation",
"prompt": "Greet the caller warmly and ask for their name",
"firstMessage": "Hello! Thank you for calling. How can I help you today?",
"label": "Greeting"
},
{
"id": "collect-info",
"type": "conversation",
"prompt": "Ask for the caller's reason for calling and collect their contact information",
"label": "Collect Information"
},
{
"id": "schedule",
"type": "tool",
"prompt": "scheduleAppointment",
"label": "Schedule Appointment"
},
{
"id": "transfer",
"type": "tool",
"prompt": "transferCall",
"label": "Transfer Call"
},
{
"id": "end",
"type": "tool",
"prompt": "endCall",
"label": "End Call"
}
],
"edges": [
{
"from": "start",
"to": "collect-info",
"when": "always"
},
{
"from": "collect-info",
"to": "schedule",
"when": "if caller wants to schedule"
},
{
"from": "collect-info",
"to": "transfer",
"when": "if caller needs support"
},
{
"from": "schedule",
"to": "end",
"when": "after scheduling"
},
{
"from": "transfer",
"to": "end",
"when": "after transfer"
}
],
"startNode": "start"
}
}
Workflow Graph Details:
-
Nodes:
-
type: "conversation"- AI-driven conversation phase -
type: "tool"- System action (must be:"scheduleAppointment","transferCall", or"endCall")
-
-
Edges: Define transitions between nodes with
whenconditions -
startNode: Must reference a node ID in the nodes array
Graphs and Flows:
-
If you provide
conversationFlow, a workflow graph is also generated in the background (non-blocking) -
If you provide
workflow, prose for a conversation flow is also generated in the background (non-blocking) -
The system stores both formats for flexibility
Activated Hours (INBOUND Only)
Important:
activatedHours
can only be set for
INBOUND
agents. OUTBOUND agents are not affected by activated hours.
{
"activatedHours": {
"timezone": "America/New_York",
"hours": [
{
"day": "monday",
"startTime": "09:00",
"endTime": "17:00"
},
{
"day": "tuesday",
"startTime": "09:00",
"endTime": "17:00"
},
{
"day": "wednesday",
"startTime": "09:00",
"endTime": "17:00"
},
{
"day": "thursday",
"startTime": "09:00",
"endTime": "17:00"
},
{
"day": "friday",
"startTime": "09:00",
"endTime": "17:00"
},
{
"day": "saturday",
"startTime": "CLOSED",
"endTime": "CLOSED"
},
{
"day": "sunday",
"startTime": "CLOSED",
"endTime": "CLOSED"
}
]
}
}
Validation Rules:
-
timezone: Must be a valid IANA timezone identifier -
day: Must be one of:monday,tuesday,wednesday,thursday,friday,saturday,sunday(case-insensitive) -
startTime/endTime:-
Format:
"HH:MM"(24-hour format) -
Or both
"CLOSED"for closed days -
endTimecan be"24:00"(end of day)
-
-
Start time must be before end time
-
CLOSED entries are filtered out (not stored in DB)
Default: If omitted, agent is "always on" (00:00-24:00 all days, UTC).
Complete Example Request
{
"name": "Customer Service Agent",
"type": "INBOUND",
"conversationFlow": "Greet the caller warmly. Ask for their name and reason for calling. If they want to schedule, use the scheduling tool. If they need support, transfer to support.",
"customInstructions": "Never mention specific prices or costs. Never give a quote over the phone.",
"voiceId": "voice-abc123",
"toolIds": ["transfer-tool-instance-456","google-cal-tool-instance-123"],
"knowledgeBaseDocumentIds": ["file-123", "file-456"],
"personality": {
"tone": "friendly",
"style": "conversational",
"useEmpathy": true
},
"firstMessage": "Hello! Thank you for calling Mario Brothers Plumbing. How can I assist you today?",
"backgroundSound": "office",
"collectFields": ["name", "phone", "email"],
"activatedHours": {
"timezone": "America/New_York",
"hours": [
{ "day": "monday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "tuesday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "wednesday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "thursday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "friday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "saturday", "startTime": "CLOSED", "endTime": "CLOSED" },
{ "day": "sunday", "startTime": "CLOSED", "endTime": "CLOSED" }
]
}
}
Response
{
"id": "agent-789",
"name": "Customer Service Agent",
"type": "INBOUND",
"businessId": "biz_123",
"conversationFlow": "Greet the caller warmly. Ask for their name and reason for calling. If they want to schedule, use the scheduling tool. If they need support, transfer to support.",
"customInstructions": "Never mention specific prices or costs. Never give a quote over the phone.",
"voiceId": "voice-abc123",
"firstMessage": "Hello! Thank you for calling Mario Brothers Plumbing. How can I assist you today?",
"backgroundSound": "office",
"collectFields": ["name", "phone", "email"],
"personality": {
"tone": "friendly",
"style": "conversational",
"useEmpathy": true,
"useHumor": false
},
"toolIds": ["transfer-tool-instance-456", "google-cal-tool-instance-123", "knowledge-base-query-tool-345"],
"knowledgeBaseDocumentIds": ["file-123", "file-456"],
"activatedHours": {
"timezone": "America/New_York",
"hours": [
{ "day": "monday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "tuesday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "wednesday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "thursday", "startTime": "09:00", "endTime": "17:00" },
{ "day": "friday", "startTime": "09:00", "endTime": "17:00" }
]
},
"workflow": null, // this is processing in the background
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
Note: When a voice agent is first created it is not yet deployed. So there is no
phoneNumber
or
onDuty
status included in the response. These fields only appear after the agent is deployed (see Step 6: Deploy the Voice Agent).
What Happens Behind the Scenes
-
Validation:
-
Business exists and belongs to your organization
-
activatedHoursis valid (if provided, must be INBOUND) -
Either
workfloworconversationFlowis provided -
toolIdsreference valid tool instances for this business
-
-
Workflow Processing:
-
If
workflowprovided: Validates graph structure, converts to prose -
If
conversationFlowprovided: Uses as-is, generates graph in background -
Creates a
Workflowrecord with both prose and graph
-
-
Structured Output (if
collectFieldsprovided):-
Creates a structured output for field extraction
-
Used to extract structured data from conversations
-
-
Voice Assistant Generation:
-
Merges workflow, tools, knowledge base, voice, personality
-
Generates voice assistant configuration
-
Auto-added tools:
-
Knowledge base query tool (if
knowledgeBaseDocumentIdsprovided) -
endCalltool (always present - cannot be disabled) -
Default
transferCalltool (if no custom transfer tool provided AND business phone exists)
-
-
-
Voice Agent:
-
Creates voice assistant
-
If this fails, the entire operation is rolled back
-
-
Database Storage:
-
Creates
Agentrecord and associated records for features, activated hours, etc.
-
Step 6: Deploy the Voice Agent
Important: Creating a voice agent does not make it live or provision a phone number. The agent exists in the system but cannot receive calls until it is deployed.
Endpoint: POST /v1/businesses/:businessId/voice-agents/:voiceAgentId/deploy
Prerequisites:
-
Agent must be created (Step 5)
Request: No body required (uses path parameters)
Response:
Returns the same agent object as
GET /voice-agents/:voiceAgentId
, but now includes deployment information:
{
"id": "agent-789",
"name": "Customer Service Agent",
"type": "INBOUND",
"businessId": "biz_123",
// ... all other agent fields ...
"phoneNumber": "+15551234567", // ← Now present! Phone number provisioned during deploy
"onDuty": true, // ← Now present! Initially on-duty after deployment
// ... rest of agent fields ...
}
Key Difference: After deployment, the response includes
phoneNumber
and
onDuty
fields that were not present in the initial creation response.
What Happens During Deployment:
-
Creates Deployment Record:
-
Creates a new deployment record (or updates existing if redeploying)
-
-
Provisions Phone Number:
-
Gets or provisions a live phone number for the business(matching business's area code when possible)
-
Stores telephony configuration in the database
-
-
Wires Phone Number to Assistant:
-
Links the voice assistant to the provisioned phone number
-
Configures webhook endpoints for call events
-
Sets up fallback destination (business's main phone number)
-
-
Activates Deployment:
-
Updates deployment status to
ACTIVEand setsonDuty: true -
Stores phone number in deployment record
-
Agent is now ready to receive or make calls
-
Important Notes:
-
Phone Number Reuse: If the business already has a provisioned phone number, it will be reused (not provisioned again)
-
Area Code Matching: The system attempts to match the phone number's area code to the business's phone number area code
Setting Agent On-Duty
After deployment, the agent is on-duty by default. To make it unavailable for calls:
Endpoint:
PATCH /v1/businesses/:businessId/voice-agents/:voiceAgentId/off
This sets
onDuty: false
, making the agent unavailable to receive calls (for INBOUND) or make calls (for OUTBOUND).
To set on-duty:
Endpoint:
PATCH /v1/businesses/:businessId/voice-agents/:voiceAgentId/on
This sets
onDuty: true
, making the agent available to receive calls (for INBOUND) or make calls (for OUTBOUND).
Note: For INBOUND agents,
activatedHours
determines when the agent is actually available. A background job will automatically toggle the agent on and off duty based on the configured activated hours.
Using Your Agent
After deployment, your agent is on-duty and ready to handle calls. How you interact with the agent depends on its type:
-
INBOUND Agents: Call the agent using the phone number provided in the deployment response. The agent will answer and handle the conversation based on your configured workflow.
-
OUTBOUND Agents: Trigger calls programmatically using the API endpoint below. The agent will call the specified phone number and handle the conversation.
Initiating Outbound Calls
For OUTBOUND agents, you can initiate calls programmatically using the following endpoint:
Endpoint: POST /v1/businesses/:businessId/voice-agents/:voiceAgentId/call
Prerequisites:
-
Agent must be created and deployed
-
Agent must be of type
OUTBOUND -
Agent must be on-duty (use
PATCH /voice-agents/:voiceAgentId/onif needed)
Request Body:
{
"phoneNumber": "+15551234567", // Required: Phone number in +1XXXXXXXXXX format
"name": "John Doe", // Optional: Name of the person being called
"leadId": "lead-123", // Optional: Lead ID to generate context from
"context": "Customer interested in plumbing services", // Optional: Custom context (used if leadId not provided)
"additionalInfo": "Mentioned they saw our ad on Google", // Optional: Additional information for the agent
"imageUrls": [ // Optional: Image URLs to send during the call; the agent will see them after the call is initiated
"https://example.com/image1.jpg",
"https://example.com/image2.jpg"
]
}
Response:
{
"success": true,
"callId": "call-record-456", // Call ID (use this to track and look up the call in call history)
"phoneNumber": "+15551234567", // Phone number that was called
"status": "initiated"
}
Request Body Fields:
-
phoneNumber(required): The phone number to call in E.164 format (+1XXXXXXXXXX). Must be a valid US phone number. -
name(optional): The name of the person being called. Used by the agent during the conversation. -
leadId(optional): If provided, the system will generate context from the lead record. This includes lead details, source, and any associated information. -
context(optional): Custom context string for the agent. Used ifleadIdis not provided. If neitherleadIdnorcontextis provided, a default context is generated. -
additionalInfo(optional): Additional information to pass to the agent. This is appended to the context. -
imageUrls(optional): Array of image URLs to send during the call. Images are sent to the agent after the call is initiated.
Validation Rules:
-
Phone number must be in E.164 format:
+1XXXXXXXXXX(US only) -
Area code and exchange code cannot start with 0 or 1
-
Agent must be OUTBOUND type
-
Agent must be deployed
-
Agent must be on-duty
What Happens:
-
Validation:
-
Validates agent exists, is OUTBOUND type, is deployed, and is on-duty
-
Validates and normalizes phone number format
-
If
leadIdprovided, verifies lead exists
-
-
Context Generation:
-
If
leadIdprovided: Generates context from lead record (includes lead details, source, etc.) -
If
contextprovided: Uses the provided context string -
If neither provided: Generates default context using business name
-
-
Call Initiation:
-
Initiates the call to the specified phone number, and will start ringing the recipient's phone
-
Creates a call record for tracking
-
If images provided, sends them to the agent after call starts
-
-
Response:
-
Returns call ID, phone number, and status
-
Example Request:
curl -X POST \
https://app.nicheandleads.com/api/partner/v1/businesses/biz_123/voice-agents/agent-789/call \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+15551234567",
"name": "John Doe",
"leadId": "lead-123",
"additionalInfo": "Customer requested a callback"
}'
Example Response:
{
"success": true,
"callId": "call-record-456",
"phoneNumber": "+15551234567",
"status": "initiated"
}
Error Responses:
-
400 BAD_REQUEST: Invalid phone number format, agent not OUTBOUND type, agent not deployed, or agent not on-duty -
404 NOT_FOUND: Agent not found or lead not found (if leadId provided) -
409 CONFLICT: Call record already exists (possible race condition with webhook) -
500 INTERNAL_ERROR: Failed to initiate call
Call History
After calls are made or received, you can retrieve call history using the following endpoints:
Business-Scoped Endpoints:
-
GET /v1/businesses/:businessId/calls- List calls for a business -
GET /v1/businesses/:businessId/calls/:callId- Get a specific call
Organization-Scoped Endpoints:
-
GET /v1/organizations/calls- List calls for an organization (optionally filter by businessId) -
GET /v1/organizations/calls/:callId- Get a specific call
Query Parameters (List Endpoints):
-
page(optional, default: 1): Page number -
page_size(optional, default: 10, max: 100): Number of results per page -
type(optional): Filter by call type -"INBOUND"or"OUTBOUND" -
status(optional): Filter by call status -"SCHEDULED","IN_PROGRESS","COMPLETED", or"FAILED" -
start(optional): Filter calls started after this date (ISO 8601 format) -
end(optional): Filter calls started before this date (ISO 8601 format) -
leadId(optional): Filter calls associated with a specific lead -
orderBy(optional): Object with optionalfield(e.g.,"startedAt","endedAt","durationMs") and optionaldirection("asc"or"desc")
Response (List):
{
"items": [
{
"id": "call-123",
"businessId": "biz_123",
"agentId": "agent-789",
"leadId": "lead-456",
"type": "OUTBOUND",
"phoneNumber": "+15551234567",
"customerNumber": "+15559876543",
"status": "COMPLETED",
"endedReason": "Call completed successfully",
"summary": "Customer interested in scheduling a service appointment",
"transcript": "Agent: Hello...",
"recordingUrl": "https://...",
"durationMs": 120000,
"structuredData": { /* extracted data */ },
"leadContext": {
"context": "Customer context...",
"generatedFromLeadId": "lead-456",
"additionalInfo": "Additional info",
"name": "John Doe",
"imageUrls": ["https://..."]
},
"startedAt": "2024-01-15T10:00:00Z",
"endedAt": "2024-01-15T10:02:00Z"
}
],
"total": 100,
"page": 1,
"page_size": 10
}
Response (Get by ID):
Returns a single call object with the same structure as items in the list response.
Example Request:
curl -X GET \
"https://app.nicheandleads.com/api/partner/v1/businesses/biz_123/calls?page=1&page_size=10&status=COMPLETED&type=OUTBOUND" \
-H "Authorization: Bearer YOUR_API_KEY"
Required Scope:
calls:read
API Reference
Base URL
https://app.nicheandleads.com/api/partner/v1
Authentication
All requests require an
Authorization
header (see OAuth):
Authorization: Bearer YOUR_API_KEY
Endpoints Summary
|
Method |
Endpoint |
Description |
|---|---|---|
|
GET |
|
List available voices |
|
GET |
|
Get specific voice |
|
GET |
|
List tool templates |
|
GET |
|
Get tool template |
|
GET |
|
List business tool instances |
|
POST |
|
Create tool instance |
|
GET |
|
Get tool instance |
|
PATCH |
|
Update tool instance |
|
DELETE |
|
Delete tool instance |
|
GET |
|
List business files |
|
POST |
|
Upload file |
|
GET |
|
Get file |
|
DELETE |
|
Delete file |
|
GET |
|
Get Google Calendar integration |
|
POST |
|
Create Google Calendar integration |
|
GET |
|
List voice agents |
|
POST |
|
Create voice agent |
|
GET |
|
Get voice agent |
|
PATCH |
|
Update voice agent |
|
DELETE |
|
Delete voice agent |
|
POST |
|
Deploy voice agent (provisions phone number) |
|
PATCH |
|
Set agent on-duty |
|
PATCH |
|
Set agent off-duty |
|
POST |
|
Initiate outbound call (outbound agents only) |
|
GET |
|
List calls for a business |
|
GET |
|
Get specific call for a business |
|
GET |
|
List calls for an organization |
|
GET |
|
Get specific call for an organization |
Last updated: 2026-01-05