Create Assistants
curl --request POST \
--url https://app.famulor.de/api/user/assistant \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"voice_id": 123,
"language_id": 123,
"type": "<string>",
"mode": "<string>",
"timezone": "<string>",
"initial_message": "<string>",
"system_prompt": "<string>"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
voice_id: 123,
language_id: 123,
type: '<string>',
mode: '<string>',
timezone: '<string>',
initial_message: '<string>',
system_prompt: '<string>'
})
};
fetch('https://app.famulor.de/api/user/assistant', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.famulor.de/api/user/assistant"
payload = {
"name": "<string>",
"voice_id": 123,
"language_id": 123,
"type": "<string>",
"mode": "<string>",
"timezone": "<string>",
"initial_message": "<string>",
"system_prompt": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.famulor.de/api/user/assistant",
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([
'name' => '<string>',
'voice_id' => 123,
'language_id' => 123,
'type' => '<string>',
'mode' => '<string>',
'timezone' => '<string>',
'initial_message' => '<string>',
'system_prompt' => '<string>'
]),
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://app.famulor.de/api/user/assistant"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"voice_id\": 123,\n \"language_id\": 123,\n \"type\": \"<string>\",\n \"mode\": \"<string>\",\n \"timezone\": \"<string>\",\n \"initial_message\": \"<string>\",\n \"system_prompt\": \"<string>\"\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))
}{
"message": "Assistant created successfully",
"data": {
"id": 789,
"name": "Sales Assistant",
"status": "inactive",
"type": "outbound",
"mode": "pipeline"
}
}
{
"message": "Validation failed",
"errors": {
"name": ["The name field is required."],
"voice_id": ["The selected voice is not compatible with the chosen engine type."],
"knowledgebase_mode": ["Only function_call mode is available for multimodal assistants."]
}
}
Create Assistants
Create a new AI assistant with specified configuration
POST
/
api
/
user
/
assistant
Create Assistants
curl --request POST \
--url https://app.famulor.de/api/user/assistant \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"voice_id": 123,
"language_id": 123,
"type": "<string>",
"mode": "<string>",
"timezone": "<string>",
"initial_message": "<string>",
"system_prompt": "<string>"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
voice_id: 123,
language_id: 123,
type: '<string>',
mode: '<string>',
timezone: '<string>',
initial_message: '<string>',
system_prompt: '<string>'
})
};
fetch('https://app.famulor.de/api/user/assistant', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.famulor.de/api/user/assistant"
payload = {
"name": "<string>",
"voice_id": 123,
"language_id": 123,
"type": "<string>",
"mode": "<string>",
"timezone": "<string>",
"initial_message": "<string>",
"system_prompt": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.famulor.de/api/user/assistant",
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([
'name' => '<string>',
'voice_id' => 123,
'language_id' => 123,
'type' => '<string>',
'mode' => '<string>',
'timezone' => '<string>',
'initial_message' => '<string>',
'system_prompt' => '<string>'
]),
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://app.famulor.de/api/user/assistant"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"voice_id\": 123,\n \"language_id\": 123,\n \"type\": \"<string>\",\n \"mode\": \"<string>\",\n \"timezone\": \"<string>\",\n \"initial_message\": \"<string>\",\n \"system_prompt\": \"<string>\"\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))
}{
"message": "Assistant created successfully",
"data": {
"id": 789,
"name": "Sales Assistant",
"status": "inactive",
"type": "outbound",
"mode": "pipeline"
}
}
{
"message": "Validation failed",
"errors": {
"name": ["The name field is required."],
"voice_id": ["The selected voice is not compatible with the chosen engine type."],
"knowledgebase_mode": ["Only function_call mode is available for multimodal assistants."]
}
}
Create a new AI assistant with specified configurationThis endpoint allows you to create a new AI assistant with comprehensive configuration options.
Engine Modes
The API supports three engine modes with different capabilities:| Mode | Description | Required Fields |
|---|---|---|
pipeline | Classic STT → LLM → TTS pipeline | llm_model_id |
multimodal | Real-time multimodal AI | multimodal_model_id |
dualplex | Multimodal “Brain” + custom TTS voice | multimodal_model_id |
Request Body
Required Core Fields
string
required
The name of the assistant (max. 255 characters)
integer
required
The voice ID for the assistant. Use the endpoint Retrieve Voices with the query parameter
mode to get compatible voices for your engine mode.integer
required
The language ID for the assistant. Use the endpoint Retrieve Languages to get available languages.
string
required
The assistant type. Options:
inbound, outboundstring
required
The engine mode. Options:
pipeline, multimodal, dualplexstring
required
The time zone of the assistant (e.g., “Europe/Berlin”, “America/New_York”)
string
required
The first message the assistant speaks at the start of the call (max. 200 characters)
string
required
The system prompt that defines the assistant’s behavior and personality
Mode-Specific Fields
integer
The LLM model ID. Required for mode
pipeline.Use the endpoint Retrieve Models to get available models.integer
The multimodal model ID. Required for modes
multimodal and dualplex.Use the endpoint Retrieve Models to get available multimodal models.integer
Fallback LLM model ID for tool calls in
multimodal/dualplex. Optional.number
Sensitivity of turn detection in
multimodal/dualplex (0-1). Default: autoSecondary Languages
integer[]
Array of additional language IDs that the assistant can speak. The assistant automatically recognizes the language and switches accordingly.
"secondary_language_ids": [2, 3, 4]
Knowledgebase Settings
integer
The knowledgebase ID to attach to this assistant
string
How to use the knowledgebase. Options:
function_call- AI calls a function to search (required for multimodal/dualplex)prompt- Knowledge is injected into prompt (pipeline only)
Organization
integer
ID of a folder to place this assistant in. Must belong to your account. Send
null to leave the assistant uncategorized.integer[]
Array of label IDs to apply to this assistant. Each label must belong to your account.
"label_ids": [3, 5]
Phone Number
integer
The ID of a phone number to assign to the assistant. Must belong to your account.
For
inbound assistants, the phone number must not be a caller ID type and must not already be assigned to another inbound assistant.Custom Mid-Call Tools
integer[]
Array of IDs for custom mid-call tools to attach. Each tool must belong to your account.
"tool_ids": [1, 5, 12]
Built-in Tools
array
Array of built-in tools. Each tool has a
type field and tool-specific fields. On Update Assistant, this replaces all existing built-in tools — pass an empty array [] to remove all tools.Show Tool Types
Show Tool Types
call_transfer - Transfer the call to another phone number
phone_number(required): Phone number to transfer todescription: When to transfer the callcustom: If true, AI can determine transfer number dynamicallytimezone: Timezone for transfer availabilitywarm_transfer: Send a message to the customer before transferring (default:false)warm_transfer_message: Prompt telling the AI what to say before transferring (e.g., “Tell the customer that the call is being transferred.”)
supervisor_phone(required): Phone number to dial for the warm transfer (e.g., “+14155552001”). Ifcustom_sipis enabled, this is a SIP address or internal extension instead.outbound_phone_id(required): ID of the phone number used to dial the supervisor. See Retrieve Phone Numbers.description(required): When to transfer — describes when the AI should initiate the warm transfer (e.g., “Transfer the call to a human supervisor when the customer requests to speak with a real person.”)custom_sip: Enable to enter a custom SIP address or internal extension instead of a phone number (default:false)caller_id_mode: What phone number the supervisor sees when receiving the call. Options:outbound_number(default — shows the outbound phone number),customer_number(shows the caller’s number),custom(shows a custom number)custom_caller_id: Custom phone number shown to supervisor. Only used whencaller_id_modeiscustom.hold_music: Audio played to the caller while on hold. Options:hold_music(default — plays default hold music),none(silence, no music)hold_music_volume: Volume level for hold music, 0–100 (default:80)hold_message: Message spoken to caller before placing them on hold (default: “Please hold while I connect you with a supervisor.”)summary_instructions: Instructions for how the AI should brief the supervisor about the call (default: “Introduce the conversation from your perspective:\n- WHO is calling (name, company if mentioned)\n- WHY they called (their goal or problem)\n- WHY a human is needed at this point\n\nKeep it brief (2-3 sentences).”)briefing_initial_message: The first message the AI says to the supervisor when they answer (default: “Hello! I have a caller on the line who needs your assistance. May I brief you on the situation?”)connected_message: Message spoken to caller after supervisor is connected (default: “You are now connected with a supervisor. I’ll leave you to it.”)
description: When the AI should end the call
description: When to use DTMF input (for IVR navigation)
timeout: Seconds to wait for input, 1–30 (default:5)stop_key: Key that ends input. Options:#(default),*
calcom_api_key(required): Your Cal.com API keycalcom_event_slug(required): The event type slug from Cal.comcalcom_team_slug: Team slug if the event belongs to a Cal.com teamcalcom_endpoint: Cal.com API region. Options:us(default —https://api.cal.com),eu(https://api.cal.eu),custom(usescalcom_custom_endpoint)calcom_custom_endpoint: Custom Cal.com API base URL. Only used whencalcom_endpointiscustom(e.g.,https://my-calcom-instance.com).calcom_booking_fields: Array of custom booking fields for the event. Each field has:slug(required),type(required, e.g. “text”, “email”, “phone”, “select”),label(required),required(default:false),options(array of options for select fields)description: When to offer scheduling
assistant_id(required): ID of the target assistant. Must belong to your account and cannot be the assistant being updated (no self-transfer).description: When to transfer (max 500 chars, default: “Transfer the conversation to this assistant when appropriate.”)message_before_transfer: Optional message the AI speaks before switching to the target assistant (max 500 chars).speak_transfer_greeting: If true, the target assistant speaks its configured initial message after the transfer completes (default:true)
"tools": [
{
"type": "dtmf_input",
"description": "Navigate IVR when needed"
},
{
"type": "warm_call_transfer",
"supervisor_phone": "+1234567890",
"outbound_phone_id": 7,
"description": "Transfer the call to a human supervisor when the customer requests to speak with a real person.",
"custom_sip": false,
"caller_id_mode": "outbound_number",
"hold_music": "hold_music",
"hold_music_volume": 80,
"hold_message": "Please hold while I connect you with a supervisor.",
"summary_instructions": "Introduce the conversation from your perspective:\n- WHO is calling (name, company if mentioned)\n- WHY they called (their goal or problem)\n- WHY a human is needed at this point\n\nKeep it brief (2-3 sentences).",
"briefing_initial_message": "Hello! I have a caller on the line who needs your assistance. May I brief you on the situation?",
"connected_message": "You are now connected with a supervisor. I'll leave you to it."
},
{
"type": "collect_keypad",
"timeout": 5,
"stop_key": "#"
},
{
"type": "assistant_transfer",
"assistant_id": 14765,
"description": "Transfer to the Support Assistant when the customer needs technical help.",
"message_before_transfer": "Sure — let me transfer you to our support specialist.",
"speak_transfer_greeting": true
},
{
"type": "end_call",
"description": "End call when done"
}
]
When you list assistants, each configured tool is returned as
{ "type": "...", "data": { ... } } with the same field names nested under data (not top-level).Voice and TTS Settings
boolean
default:"true"
Whether emotional text-to-speech synthesis is enabled
number
default:"0.70"
Voice stability (0-1). Higher = more consistent
number
default:"0.50"
Voice similarity (0-1). Higher = closer to the original
number
default:"1.00"
Speech speed multiplier (0.7-1.2)
number
default:"0.10"
LLM temperature (0-1). Lower = more deterministic
integer
Custom TTS provider ID. If not set, selected automatically based on language. See Retrieve Synthesizer Providers.
integer
Custom STT provider ID. If not set, selected automatically based on language. Only for
pipeline. See Retrieve Transcriber Providers.Call Behavior Settings
boolean
default:"true"
Whether interruptions from the caller are allowed.
Cannot be disabled for
multimodal and dualplex.boolean
default:"false"
Whether filler audio should be used during processing (e.g., “uh”, “just a moment”).
Only available in
pipeline mode.object
Custom filler profiles per category. If not specified, language-dependent defaults are used. Each category is an array of short phrases.
positive: Fillers for affirmative responses (e.g., “Great!”, “Perfect!”)negative: Fillers for negative/neutral responses (e.g., “Hmm.”, “Mhm.”)question: Fillers while processing a question (e.g., “Good question.”, “One moment.”)neutral: Fillers for neutral acknowledgments (e.g., “Okay.”, “Understood.”)
"filler_config": {
"positive": ["Great!", "Perfect!", "Very good!"],
"negative": ["Hmm.", "Understood.", "Okay."],
"question": ["Good question.", "One moment.", "Let me check."],
"neutral": ["Okay.", "Understood.", "Noted."]
}
boolean
default:"false"
Whether the call should be recorded
boolean
default:"true"
Whether noise cancellation should be enabled
boolean
default:"false"
If true, the assistant waits for the customer to speak first
Timing Settings
integer
default:"600"
Maximum call duration in seconds (20-1200)
integer
default:"40"
Maximum silence duration until re-engagement in seconds (1-360)
integer
Maximum silence directly after call start before termination (1-120 seconds). Optional.
integer
default:"30"
Maximum ringing time before canceling (1-60 seconds)
Re-Engagement Settings
integer
default:"30"
Re-engagement interval in seconds (7-600)
string
Custom prompt for re-engagement messages (max. 1000 characters)Example:
"Are you still there? Do you have any other questions?"Voicemail Settings
boolean
default:"true"
Whether to end the call if voicemail is detected
string
Message to leave on voicemail (max. 1000 characters)
Endpoint Detection
string
default:"vad"
Voice activity detection type. Options:
vad, ainumber
default:"0.5"
Endpoint sensitivity (0-5)
number
default:"0.5"
Interrupt sensitivity (0-5)
integer
Minimum number of words before interruption is allowed (0-10). Set to enable.
Ambient Sound
string
Background ambient sound. Options:
off, office, city, forest, crowded_room, cafe, naturenumber
default:"0.5"
Ambient sound volume (0-1)
Webhook Configuration
boolean
default:"false"
Whether webhook notifications are enabled
string
The webhook URL for post-call notifications. Required if
is_webhook_active is true.boolean
default:"true"
Whether to send webhooks only for completed calls (not for failed/no-answer)
boolean
default:"true"
Whether to include the recording URL in the webhook payload
Post-Call Evaluation
boolean
default:"true"
Whether AI post-call evaluation is enabled
array
Schema definition for post-call data extraction
Show post_call_schema Properties
Show post_call_schema Properties
"post_call_schema": [
{"name": "status", "type": "bool", "description": "Whether the call objective was met"},
{"name": "summary", "type": "string", "description": "Brief summary of the call"}
]
Variables
object
Key-value pairs of custom variables that can be used in prompts via
{{variable_name}}"variables": {
"company_name": "Acme GmbH",
"product": "Premium Widget",
"support_email": "support@acme.com"
}
Conversation-Ended Settings
integer
default:"30"
Minutes of chat inactivity before the conversation is considered ended (1–1440)
boolean
default:"false"
Whether the conversation can be restarted after inactivity end
string
Webhook URL invoked when a chat conversation ends due to inactivity. Separate from the call webhook.
Example Requests
pipeline Mode Assistant
{
"name": "Sales Assistant",
"voice_id": 1,
"language_id": 1,
"type": "outbound",
"mode": "pipeline",
"timezone": "Europe/Berlin",
"initial_message": "Hello! How can I assist you today?",
"system_prompt": "You are a professional sales assistant...",
"llm_model_id": 2,
"secondary_language_ids": [2, 3],
"knowledgebase_id": 1,
"knowledgebase_mode": "prompt",
"fillers": true,
"filler_config": {
"positive": ["Great!", "Perfect!", "Very good!"],
"negative": ["Hmm.", "Understood."],
"question": ["Good question.", "One moment."],
"neutral": ["Okay.", "Noted.", "Understood."]
},
"tool_ids": [1, 5],
"tools": [
{"type": "dtmf_input", "description": "Navigate IVR when needed"},
{
"type": "warm_call_transfer",
"supervisor_phone": "+1234567891",
"outbound_phone_id": 7,
"description": "Transfer the call to a human supervisor when the customer requests to speak with a real person.",
"custom_sip": false,
"caller_id_mode": "outbound_number",
"hold_music": "hold_music",
"hold_music_volume": 80,
"hold_message": "Please hold while I connect you with a supervisor.",
"summary_instructions": "Introduce the conversation from your perspective:\n- WHO is calling (name, company if mentioned)\n- WHY they called (their goal or problem)\n- WHY a human is needed at this point\n\nKeep it brief (2-3 sentences).",
"briefing_initial_message": "Hello! I have a caller on the line who needs your assistance. May I brief you on the situation?",
"connected_message": "You are now connected with a supervisor. I'll leave you to it."
},
{"type": "collect_keypad", "timeout": 5, "stop_key": "#"},
{
"type": "assistant_transfer",
"assistant_id": 14765,
"description": "Transfer to the Support Assistant when the customer needs technical help.",
"message_before_transfer": "Sure — let me transfer you to our support specialist.",
"speak_transfer_greeting": true
},
{"type": "end_call", "description": "End call when the customer is satisfied"}
],
"reengagement_interval": 20,
"reengagement_prompt": "Are you still there?"
}
multimodal Mode Assistant
{
"name": "Support Bot",
"voice_id": 41,
"language_id": 1,
"type": "inbound",
"mode": "multimodal",
"timezone": "America/New_York",
"initial_message": "Hi! Welcome to support.",
"system_prompt": "You are a helpful support agent...",
"multimodal_model_id": 1,
"chat_llm_fallback_id": 2,
"turn_detection_threshold": 0.7,
"knowledgebase_id": 1,
"knowledgebase_mode": "function_call",
"tts_emotion_enabled": false
}
dualplex Mode Assistant
{
"name": "Premium Agent",
"voice_id": 1,
"language_id": 2,
"type": "outbound",
"mode": "dualplex",
"timezone": "Europe/Berlin",
"initial_message": "Good day!",
"system_prompt": "You are a professional assistant...",
"multimodal_model_id": 4,
"chat_llm_fallback_id": 2,
"secondary_language_ids": [1, 3],
"knowledgebase_id": 1,
"knowledgebase_mode": "function_call",
"ambient_sound": "office",
"ambient_sound_volume": 0.3
}
Response
string
Success message confirming the creation of the assistant
object
{
"message": "Assistant created successfully",
"data": {
"id": 789,
"name": "Sales Assistant",
"status": "inactive",
"type": "outbound",
"mode": "pipeline"
}
}
{
"message": "Validation failed",
"errors": {
"name": ["The name field is required."],
"voice_id": ["The selected voice is not compatible with the chosen engine type."],
"knowledgebase_mode": ["Only function_call mode is available for multimodal assistants."]
}
}
Notes
- All required fields must be provided for successful creation
- Use the endpoint Retrieve Voices with the query parameter
modeto obtain compatible voices - For
multimodal/dualplex,knowledgebase_modemust be set tofunction_call - For
multimodal/dualplex,allow_interruptionsis always enabled fillersis only available inpipelinemode- New assistants are created with status
inactiveby default
⌘I