PATCHhttps://core-api.heysadie.ai/assistants/{id}
id name voiceId transcriberId modelId developerPrompt parameters recordingEnabled failoverNumber failoverMode phoneNumberId 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 createdAt updatedAt featureFlags metadata timestamp version path error code message details fieldUpdate assistant
Try it in the API ExplorerExample request
curl -X PATCH "https://core-api.heysadie.ai/assistants/ASSISTANT_ID" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"voiceId": "0195f1e2-0000-7000-8000-000000000000",
"transcriberId": "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
Path parameters
idstringrequiredThe resource's UUID.
Body application/json · required
namestringoptionalDisplay name of the assistant (e.g., Sadie, Alex)
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
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. Merged into settings.transferDialTimeout; other 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. Merged into settings.warmWhisperDelaySeconds; other 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