POSThttps://core-api.heysadie.ai/assistants
voiceId transcriberId modelId developerPrompt parameters recordingEnabled failoverNumber failoverMode phoneNumberId name firstMessage toolIds timezone address endOfCallMessage phoneNumberPassThrough summaryPrompt structuredDataPrompt categories promptId chatPromptId whisperSummaryPromptId voicePersonaPromptId backgroundSound serverUrl notifications csatFeedback idleMessages transferMode callTimeLimitSeconds idleTimeoutSeconds idleMessageMaxSpokenCount settings transferDialTimeout warmWhisperDelaySeconds warmReturnMessage taskDrivenMode transferSettings dictionaryIds dictionarySettings ivrSettings success data id createdAt updatedAt featureFlags metadata timestamp version path error code message details fieldCreate assistant
Create a new assistant that will handle calls on behalf of your business (restaurant, hotel, car rental, etc). > ⚠️ **Important-Note:** All newly created assistants are automatically provisioned on **Core-V2**, which introduces enhanced latency performance and improved voice quality. --- You can configure its voice, behavior, tools, phone logic, and how it summarizes or classifies the calls. - `name`: The display name of the assistant (e.g., "Sadie", "Alex"). - `voiceId`: The voice the assistant will use to speak. - `transcriberId`: The engine used to convert speech to text. - `modelId`: The LLM that powers the assistant's logic and responses (e.g., GPT-4). - `developerPrompt`: Lets you inject your own section into the default system prompt. Example: "Always ask for membership ID before confirming a reservation." - `parameters`: A JSON object with dynamic values like `{{opening_hours}}` or `{{branch_name}}`. These values can be inserted in the prompt. - `recordingEnabled`: Boolean. If true, calls are recorded. - `failoverNumber`: The phone number to forward the call to if the assistant fails or needs to escalate. - `failoverMode`: Boolean. If true, the call will be forwarded to the failover number. - `phoneNumberId`: ID of the number this assistant is linked to. - `firstMessage`: What the assistant says at the start of the call. Example: "Hi! You've reached Joe's Pizza. How can I help?" - `toolIds`: List of tool IDs the assistant is allowed to use during a call. - `timezone`: The timezone of the business (e.g., "Australia/Sydney"). - `address`: The business address. - `endOfCallMessage`: The last thing the assistant says before hanging up. Example: "Thanks for calling, have a great day!" - `phoneNumberPassThrough`: If true, the assistant can use the caller's number during the call (e.g., "Would you like to use the number ending in 595?"). If false, it will always ask for the number. - `summaryPrompt`: A prompt to guide how the assistant summarizes the call at the end. Can be made short, long, or focused on certain topics. - `structuredDataPrompt`: Works with `categories` to define when the assistant should classify a call as "booking", "edit", "cancel", etc. - `categories`: A list of string values representing what type of call this is. Example: ["booking", "edit", "cancel"] - `promptId`: The ID of the prompt associated with the assistant, if not provided the default prompt will be used. - `backgroundSound`: Whether the assistant has a background sound. - `serverUrl`: The webhook URL override for the assistant. - `notifications`: Array of notification webhook URLs. New URLs will be appended to existing ones (not replaced). - `csatFeedback`: Whether CSAT (Customer Satisfaction) feedback is enabled for this assistant. Defaults to false if not provided. - `transferMode`: Transfer mode behavior for escalations. One of `cold-transfer`, `smart-summary`, `warm-return`. Any other value is rejected with a 400. Defaults to `cold-transfer`. - `warmWhisperDelaySeconds`: Warm-transfer whisper delay in seconds. Integer from 0 to 30. Defaults to 0 when omitted. - `settings`: (Optional) Per-assistant settings container. Currently holds `conversationConfig`; additional setting categories will be added here in the future. - `conversationConfig`: Conversation timing configuration with four optional sub-plans: - `endpointingPlan`: `mode` ("fixed" | "dynamic" (dynamic adapts the delay to the caller's pause pacing), `minDelay` / `maxDelay`) silence thresholds (seconds) before the agent responds. - `turnDetectionPlan`: `timeout` (seconds) and `unlikelyThreshold` (0-1 probability). - `vadPlan`: `minSpeechDuration`, `minSilenceDuration`, `prefixPaddingDuration`: low-level VAD in seconds. - `interruptionPlan`: `minDuration` (0-5 seconds of sustained caller speech before a barge-in stops the agent) and `minWords` (0-10 transcribed words required to register an interruption). - `deliveryMode`: Speech delivery style: `"none"` (default), `"emotion_tagging"`, or `"expressive"`. - `"emotion_tagging"`: Adds consistent delivery using emotion tags picked by a classifier (at most one per response). Works with Cartesia Sonic 3 and 3.5, and ElevenLabs v3; other voice models use their normal delivery. English calls only. - `"expressive"`: The AI controls its own delivery per response: emotion, pacing, pauses, and natural sounds. Works with Cartesia and Fish Audio voices; other voice models use their normal delivery. - `expressiveOptions`: (Only used when `deliveryMode` is `"expressive"`.) Sparse overrides on the default expressive behavior: omitted fields keep the defaults (full sound vocabulary, light fillers, delivery matched to the moment). Set to `null` to clear all overrides. - `disfluencies`: Filler words such as "um" / "uh". Defaults to on; set `false` to opt out. - `nonverbalSounds`: `true` keeps every sound, `false` disables all, or an object toggling categories individually: `laughing`, `breathing`, `sighing`, `crying`, `vocalizing` (humming, sing-song), `mouthSounds` (tsk, tongue-click), `reflexSounds` (cough, throat-clear, yawn). - `pace`: `"slow"` | `"normal"` | `"fast"`. Omit to let the AI pace itself. - `instructionsAppend`: Free-text delivery rules added on top of the defaults (max 2000 chars). - `emotionTaggingEnabled`: Legacy boolean opt-in for emotion tagging, superseded by `deliveryMode`. Still honored when `deliveryMode` is absent. All fields optional. Omitted values use agent defaults. Set to `null` to clear. Example: a restaurant assistant with a friendly tone, set to timezone "Europe/London", uses tools like "GetMenu" and "BookTable", and always ends with "Thanks for calling, enjoy your meal!" Make sure your `parameters` match what's inside your developerPrompt: e.g., if you write "We are open {{opening_hours}}", then `parameters` should include `{ "opening_hours": "10am to 10pm" }`.
Try it in the API ExplorerExample request
curl -X POST "https://core-api.heysadie.ai/assistants" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"voiceId": "0195f1e2-0000-7000-8000-000000000000",
"transcriberId": "0195f1e2-0000-7000-8000-000000000000",
"modelId": "0195f1e2-0000-7000-8000-000000000000"
}'Authentication
Authenticate with an API key in the Authorization header using the ApiKey scheme. See Authentication for how keys work and where to get them.
AuthorizationstringrequiredAPI key in the ApiKey scheme: ApiKey YOUR_API_KEY. Tenant keys authorize their own tenant; organization keys can act on any tenant in the organization.
X-Tenant-Idstring (uuid)optionalRequired when authenticating with an organization key: it selects the tenant the request acts on. Omit with tenant keys.
Request
Body application/json · required
voiceIdstring (uuid)optionalThe voice the assistant will use to speak to callers
transcriberIdstring (uuid)optionalThe transcriber engine used to convert speech to text
modelIdstring (uuid)optionalThe LLM model that powers the assistant's reasoning (e.g., GPT-4)
developerPromptstringoptionalCustom prompt section developers can inject into the default assistant prompt
parametersanyoptionalJSON object with dynamic values injected into developerPrompt (e.g., {{opening_hours}})
recordingEnabledbooleanoptionalWhether call recordings are enabled for this assistant
failoverNumberstringoptionalThe phone number to transfer calls to if the assistant fails to respond (E.164 format)
failoverModebooleanoptionalTurn on or off the failover mode (in case it's enabled, the call will be forwarded to the failover number)
phoneNumberIdstring (uuid)optionalThe phone number this assistant is assigned to
namestringoptionalDisplay name of the assistant (e.g., Sadie, Alex)
firstMessagestringoptionalThe first message the assistant says when answering the call
toolIdsstring (uuid)[]optionalList of tool IDs the assistant can use
timezonestringoptionalTimezone of the business the assistant is handling calls for (e.g., Australia/Sydney)
addressstringoptionalAddress of the business (used in prompt reasoning)
endOfCallMessagestringoptionalFinal message before the call ends
phoneNumberPassThroughbooleanoptionalWhether the assistant can read and reference the caller's phone number if not anonymous
summaryPromptstringoptionalPrompt used to control how the assistant summarizes the call transcript
structuredDataPromptstringoptionalPrompt that helps classify calls based on the categories field
categoriesstring[]optionalList of categories the assistant can classify the call into (e.g., booking, edit)
promptIdstring (uuid)optionalThe ID of the prompt associated with the assistant
chatPromptIdstring (uuid) | nulloptionalOptional chat/messaging prompt ID (type 'chat'); null clears it
whisperSummaryPromptIdstring (uuid) | nulloptionalOptional whisper-summary prompt ID (type 'whisper_summary'); null clears it
voicePersonaPromptIdstring (uuid) | nulloptionalOptional voice persona prompt ID (type 'voice_persona', realtime models); null = runtime default persona
backgroundSoundbooleanoptionalWhether the assistant has a background sound
serverUrlstring | nulloptionalThe webhook URL override for the assistant; null clears it
notificationsstring[]optionalArray of notification webhook URLs for the assistant
csatFeedbackbooleanoptionalWhether CSAT (Customer Satisfaction) feedback is enabled for this assistant
idleMessagesstring[]optionalArray of messages to send when the assistant detects the caller is idle
transferModeenumoptionalTransfer mode behavior for escalations. Accepts exactly 'cold-transfer', 'smart-summary', or 'warm-return'; any other value is rejected with a 400. Matched exactly and case-sensitively. Defaults to 'cold-transfer' if not provided. 'smart-summary' briefs the destination then connects the caller; 'warm-return' briefs the destination and returns the caller to the assistant if nobody answers.
"cold-transfer""smart-summary""warm-return"callTimeLimitSecondsstring (integer) | integeroptionalMaximum call duration in seconds. Must be between 10 and 43200 (12 hours). Null means no limit.
idleTimeoutSecondsstring (integer) | integeroptionalNumber of seconds to wait before considering the caller idle. Min 0 - Max 60.
idleMessageMaxSpokenCountstring (integer) | integeroptionalMaximum number of times idle messages can be spoken before ending the call. Min 0 - Max 10.
settingsanyoptionalPer-assistant settings container. Currently holds conversationConfig; additional setting categories will be added here in the future. Structure: { conversationConfig: { endpointingPlan?: { mode?: "fixed"|"dynamic", minDelay?, maxDelay? }, turnDetectionPlan?: { timeout?, unlikelyThreshold? }, vadPlan?: { minSpeechDuration?, minSilenceDuration?, prefixPaddingDuration? }, interruptionPlan?: { minDuration? (0-5), minWords? (0-10) }, deliveryMode?: "none"|"emotion_tagging"|"expressive", expressiveOptions?: { disfluencies?: boolean, nonverbalSounds?: boolean | { laughing?, breathing?, sighing?, crying?, vocalizing?, mouthSounds?, reflexSounds? }, pace?: "slow"|"normal"|"fast", instructionsAppend?: string (max 2000) } | null, emotionTaggingEnabled?: boolean (legacy; superseded by deliveryMode) } }
transferDialTimeoutstring (integer) | integeroptionalDial timeout in seconds for transfer attempts. Integer between 1 and 60. Stored under settings.transferDialTimeout (existing settings keys are preserved).
warmWhisperDelaySecondsstring (integer) | integeroptionalPause in seconds before the warm-transfer whisper plays to the supervisor. Integer between 0 and 30. Defaults to 0 when omitted. Stored under settings.warmWhisperDelaySeconds (existing settings keys are preserved).
warmReturnMessagestringoptionalWhat the assistant says when a warm-return transfer goes unanswered and the caller comes back. Max 2000 characters. Merged into settings.warmReturnMessage; other settings keys are preserved. Send "" to restore the built-in wording. Set this to match whatever your server does when it receives supervisor_answered: false on the end-of-call report.
taskDrivenModebooleanoptionalWhen true, CoreProxy leaves {tool_instructions} empty and sends linked taskgroups/tasks as structured data to AgentSpawn. When false (default), the existing prompt pipeline runs unchanged.
transferSettingsmap<string, any> | nulloptionalTransfer knobs for this assistant, stored in the transfer_settings column. Structure: { amd_detection?: boolean, use_assistant_number?: boolean }. Unknown keys are rejected. This DEEP-MERGES on PATCH, so sending one knob leaves the others as stored; send null to clear the whole document. amd_detection controls answering-machine detection on a warm-return transfer destination and defaults to on when absent. Turning it off does not merely skip detection: the caller stays bridged to whatever answered, voicemail included, instead of being returned to the assistant. use_assistant_number controls the caller ID shown to the person receiving a cold or warm transfer and defaults to false when absent. When false, they see the customer's phone number, or the assistant's number if the customer withheld theirs. When true, they always see the assistant's own phone number, which is the number the customer called, so they can tell the call is a transfer. The tradeoff is that the customer's number is then not shown on their phone.
dictionaryIdsstring (uuid)[]optionalTenant dictionaries to link, in precedence order. Replaces the whole set; [] unlinks all. A dictionary's own type decides whether its entries bias the transcriber or shape pronunciation.
dictionarySettingsmap<string, any> | nulloptionalPer-assistant STT keyterms and TTS pronunciation rules. Rules are provider-neutral: `phonemes` is space-separated IPA rendered per TTS model, `respell` is the plain-text fallback; at least one is required. Example: {"sttKeyterms":[{"term":"Gree","language":null}],"ttsPronunciations":[{"word":"Quatre","respell":"Kate","phonemes":"k a t","language":"fr"}]}. Replace semantics: send the whole object; null clears. Zod enforces the real shape.
ivrSettingsmap<string, any> | nulloptionalIVR router configuration for this assistant. Free-form JSON object; no inner structure is validated yet while the feature is in progress. On PATCH this DEEP-MERGES into the stored document, so sending one key leaves the others as stored: no read-modify-write needed. Per-key removal is not expressible: a key sent as null is stored as null, which every consumer reads as unset. Send the whole field as null to clear the document (null = no IVR configured). Omit the field to leave it unchanged.
Responses
successbooleanrequiredtrue on every 2xx
dataobjectoptionalThe result
Show 42 child properties
idstringrequirednamestringrequiredfirstMessagestringrequiredvoiceIdstring | nullrequiredtranscriberIdstring | nullrequiredmodelIdstring | nullrequireddeveloperPromptstring | nullrequiredparametersanyrequiredrecordingEnabledbooleanrequiredfailoverNumberstring | nullrequiredfailoverModebooleanrequiredphoneNumberIdstring | nullrequiredcreatedAtstring (date-time) | string (date) | number | nullrequiredupdatedAtstring (date-time) | string (date) | number | nullrequiredtoolIdsstring[] | nullrequiredtimezonestringrequiredaddressstring | nullrequiredendOfCallMessagestring | nullrequiredphoneNumberPassThroughbooleanrequiredsummaryPromptstring | nullrequiredstructuredDataPromptstring | nullrequiredcategoriesstring[] | nullrequiredpromptIdstring | nullrequiredchatPromptIdstring | nulloptionalwhisperSummaryPromptIdstring | nulloptionalvoicePersonaPromptIdstring | nulloptionalbackgroundSoundbooleanrequiredserverUrlstring | nullrequiredcsatFeedbackbooleanrequirednotificationsanyrequiredidleMessagesanyrequiredtransferModeanyrequiredcallTimeLimitSecondsnumber | nullrequiredidleTimeoutSecondsnumber | nullrequiredidleMessageMaxSpokenCountnumber | nullrequiredsettingsany | nullrequiredtaskDrivenModeboolean | nulloptionalfeatureFlagsmap<string, boolean>optionalivrSettingsany | nulloptionaltransferSettingsany | nulloptionaldictionarySettingsany | nulloptionaldictionaryIdsstring[]optionalmetadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
400The request is invalid. `details` lists each field that failed
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 3 child properties
codeenumrequiredA parameter or body field broke a rule
"VALIDATION_ERROR"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
detailsobject[]optionalOne entry per field that failed
Show 2 item properties
fieldstringrequiredThe offending field
messagestringrequiredThe rule it broke
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
401Missing or invalid credentials
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredNo valid credentials
"UNAUTHORIZED"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
403The credentials are valid but may not use this route
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredThe credentials may not use this route
"FORBIDDEN"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
404Not found, or outside the caller's scope
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredAn id names nothing the caller can see
"RESOURCE_NOT_FOUND"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
500An unexpected server error
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredAn unexpected server failure
"INTERNAL_SERVER_ERROR"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested