Agent field reference

Agent field reference

Every field POST /api/agents and PUT /api/agents/{id} accept, what each one defaults to when you leave it out, and which ones are refused. This is the companion to Agents API — that page is the endpoints and the workflow; this page is the exhaustive field list.

Three rules apply to everything below, and most create-time confusion comes from not knowing them:

  1. Requests are camelCase; the agent object you read back is snake_case. You send ttsVoice, s2sConfig, sessionConfig; you read tts_voice, s2s_config, session_config. Reading an agent and posting it straight back is safe — unrecognised keys are ignored.
  2. Config objects are replaced whole, never merged. llmConfig, sttConfig, ttsConfig, s2sConfig, telephonyConfig, fallbackConfig, sessionConfig, metadata and tags each store exactly what you send. Sending {"sessionConfig": {"maxDuration": 600}} on an update erases every other session key. Read the agent first, change the one key, send the whole object back.
  3. On update, null means "leave unchanged" — not "clear". To clear a config object send {}. This catches people trying to switch the realtime engine off with "s2sConfig": null, which does nothing at all.

Top-level fields

Required on create. Omitting any of these is a 422 from the JSON decoder before any of our validation runs, so the message names the missing field rather than explaining the concept.

FieldTypeNotes
namestringDisplay name. Not required to be unique.
llmProviderstringe.g. openai, anthropic, groq, customllm, customapi.
llmModelstringModel id for that provider.
sttProviderstringSpeech-to-text provider.
ttsProviderstringText-to-speech provider.
ttsVoicestringVoice id offered by that TTS provider.
sessionConfigobjectRuntime behaviour. {} is valid and is the normal starting value — every key inside it is optional. See below.

The five cascade fields stay required even for a realtime (speech-to-speech) agent. s2sConfig names an engine to try: the call builds STT, LLM and TTS first and only then attempts the realtime bind, so a blank cascade slot fails the bind and kills the call whichever engine you picked. See when the cascade runs instead.

Optional on create. Every one of these is also optional on update.

FieldTypeDefault when omitted
descriptionstringnull
systemPromptstringnull — the agent runs with no persona instructions
isPublicbooleanfalse
llmConfigobjectnull. Provider-specific settings (temperature, maxTokens, BYOK apiKey, …)
sttConfigobjectnull
ttsConfigobjectnull
s2sConfigobjectnull — cascade only. See realtime agents
fallbackConfigobjectnull — no chain. Keys the schema doesn't name are dropped on write, so a pasted apiKey never reaches the column
telephonyProviderstringnull
telephonyConfigobjectnull. Carrier credentials, opener, who speaks first, AMD, voicemail
tagsarray or objectnull
metadataobjectnull. Almost every feature toggle lives here — see below

Update-only. isActive (boolean) pauses or resumes an agent. It cannot be set at create; a new agent is always active.

Not settable through this API at all. orgId comes from your key. userId is stamped as the creator. partnerClientId is write-once and reachable only from the internal reseller route — it decides whose usage rollup and whose spend limits the agent bills against, so it is deliberately not a request field.

What is and is not validated at create

This is the single biggest source of "why did my agent not work" tickets. 201 Created does not mean your provider ids are correct.

FieldChecked at create?
s2sConfig provider / model / voiceYes — validated against GET /api/catalog/s2s. A bad combination is a 400 here, not a failed call later.
s2sConfig.fallbackYes — an agent with fallback: false and no reachable realtime key is refused.
metadata.piiPolicyYes — an unsatisfiable policy (e.g. never-store without keypad detection) is a 400.
llmProvider, llmModel, sttProvider, ttsProvider, ttsVoiceNo. Stored exactly as sent. A typo returns 201 and the first symptom is a call that will not connect.
telephonyProvider / telephonyConfigNo.
Everything inside sessionConfigNo — see the lenient-decode note below.

Check provider ids against GET /api/catalog before you write them. After a save, a background voice-stack preflight runs and flags a broken provider on the agent's health badge — it reports, it does not block.

Unknown keys are silently ignored, everywhere. There is no strict-mode. A misspelled maxDurationSecs inside sessionConfig is not an error; it is simply never read. Read the agent back and diff it against what you sent if a setting is not taking effect.

sessionConfig

Runtime behaviour for every call this agent takes. All keys optional; {} is a complete, valid value.

Lenient decode. Several keys degrade to their default when sent as the wrong type instead of failing the request. This exists because a single bad key used to make the whole sessionConfig fail to deserialize, which silently dropped every other setting for the call. The trade-off is that a wrong type is invisible — no error, just the default.

Call length and context

KeyTypeDefault when absent
maxDurationinteger, secondsNo cap
maxDurationMessagestringNot a silent cut — a built-in sign-off in that leg's language. Set this to override the wording. A silent cut is kept only where a spoken line would be wrong: a human-to-human softphone bridge, the text plane, a warm-transfer bridge, and a realtime leg the cascade TTS must not talk over
memoryTypeephemeral | short-term | long-termAlso accepted as memory_type — the builder writes snake_case here and both spellings work
contextModewindow | full | summaryDerived from contextWindow: 0full, otherwise window
contextWindowinteger, turns10 when contextMode is window

Silence and turn-taking

KeyTypeDefault when absent
silenceHangupSecsinteger, secondsDisabled. 0 also disables. The watchdog re-prompts but never hangs up
silenceHangupMessagestringA built-in goodbye line
silenceCheckinobjectON at 20 s. Absent is not "off" — send the object to change the delay or disable it. The "Are you there?" line is generated in the caller's language; a static message overrides
bargeInSensitivityfloat 0.01.00.5 (≈18 dB SNR). 0.0 = hard to interrupt (≈28 dB), 1.0 = yields at the slightest sound (≈8 dB). Lenient: a non-numeric value degrades to the default
rememberInterruptionsbooleanfalse — a reply the caller cut off is dropped from context. When on, the part the caller actually heard is kept, tagged "(interrupted)"
turnTakingobjectThe deployment's global smart-turn behaviour, unbilled. An explicit tier is billable and takes effect only under the deployment's turn-tier flags
backchannelobjectOff. Agent-side "mm-hmm" dropped into the caller's micro-pauses while they monologue
defendobjectOff. Holds the floor with "let me finish that first…" when a caller talks over a must-deliver clause. Requires Smart-Turn v2 on the deployment

Latency cover

KeyTypeDefault when absent
fillersobjectOff, zero overhead. A short language-matched "one sec…" when the LLM is slow to first token
delayedResponseobjectOff. The tiered "thinking hold" that generalizes fillers — Tier 1 filler line, Tier 2 hold-music bed, Tier 3 periodic reassurance, plus a hard t_max_ms cap. Cause-agnostic by design: the caller hears silence, not "reasoning"
ringSoundobjectOff — the agent speaks immediately. Plays a ringback for a few seconds before the first words, configurable per call direction
backgroundSoundobjectOff, zero overhead. Continuous synthetic ambience (coffee shop, office, call center, traffic) mixed under the agent's TTS

Behaviour and channel

KeyTypeDefault when absent
behaviorobjectAll off. Personality/tone, accuracy/format and trust/safety toggles appended to the system prompt per turn
personaGenderfemale | male | neutralUnset. Drives grammatical agreement so the model inflects first-person verbs and adjectives to match the voice in languages that mark speaker gender (Hindi, Urdu, Punjabi, Gujarati, Marathi, Spanish, French, Portuguese, Italian, Arabic, Hebrew, Russian, …). Mirrors metadata.gender
keypadInputobjectPer-digit [DTMF] annotation only. When set, digits are buffered and flushed as one turn on inter-digit timeout, termination key or digit limit. Lenient: a bare true coerces to {enabled: true}
optOutbooleanON. Only an explicit false removes it. Governs both the opt_out tool and the deployment's DTMF opt-out digit — an agent that does not do opt-out should not have one of its keypad digits quietly repurposed either
followupobjectOff. Gives the LLM a schedule_followup_call tool for "call me back tomorrow at 5". Telephony only — on web and simulation sessions the tool politely declines, since there is no number to dial back. Lenient
transportwebsocket | webrtcwebsocket. webrtc (LiveKit) needs the server built with the webrtc feature plus LIVEKIT_* env, and falls back to websocket otherwise
debugTracebooleanON. Records a full start→end event trace per call when the backend has DEBUG_TRACE_ENABLED. Only an explicit false disables it

Note the three keys whose absent value is on, not off: optOut, debugTrace, and silenceCheckin.

metadata

A free-form object. Anything you put here is stored, but the keys below are the ones the platform reads. Tool secrets inside it are encrypted at rest on write and decrypted on read by members of the owning org.

Behaviour

KeyShapeWhat it does
toolsarrayFunction calling, including call transfer. See Tools & function calling
precallLookupsarrayFetches run before the greeting, so the agent opens already knowing the caller
variablesobject{placeholder} substitution. See Context variables
voicemailMessagestringLeft on an answering machine. Blank or absent means leave no voicemail — both builders promise that, so an empty string is never spoken as an empty line
callerIdentity{enabled, label?}Marks the caller as verified for downstream rules
objectivesobjectStateful context: slots the call tries to establish, tools it must actually run, disposition grading. Caps: 30 slots, 20 actions, 12 dispositions, values truncated at 400 chars, enums at 24 values. Defaults off
piiPolicy{rules: {slug: {disposition, fieldKey?}}}Per-agent PII handling. Validated at create — a malformed rule is dropped rather than defaulted, and an unsatisfiable combination is a 400
channelsarray of web / telephonyWhich channels the agent serves. Informational today — it does not yet disable call paths
genderstringMirror of sessionConfig.personaGender
timezoneIANA zone stringThe agent's local time. utcOffsetMinutes is the legacy fixed-offset form — it still works but cannot follow DST

After the call

KeyShapeWhat it does
postCallAnalysis{enabled, minDurationSec, minCustomerTurns, customFields[], qaCriteria[], model?}Summary, sentiment, disposition, QA rubric, LLM-judge scorecard. Defaults off, which is why an app reading calls with includeAnalysis=true sees analysis: null on every row. Caps: 30 custom fields, 30 QA criteria. minDurationSec (default 20) and minCustomerTurns (default 2) skip calls too short to be worth an AI pass. See Post-call analysis
callerMemory{enabled, ttlDays}Remembers callers across calls. ttlDays is clamped to 1–3650, default 90. See Caller memory
postCallWhatsApp{enabled, …}Sends a WhatsApp message after the call

Flow agents

KeyShapeWhat it does
flowobjectThe published multi-context graph. See Flow agents
flowDraft, flowDraftGlobalsobjectUnpublished working copy
configPublishedAt, flowPublishedAtRFC-3339 stringBuilder-owned. These are what the status=draft / status=published list filter compares against

Housekeeping

environment (dev / staging / prod) is what the ?env= list filter matches. icon and logoKey are branding. createdByApp is the ownership stamp the app-agent plane scopes on — it is set by the platform and no app may write it, at any scope.

Booleans in metadata are read leniently

enabled flags on postCallAnalysis, callerMemory, postCallWhatsApp and objectives accept a real boolean or the strings true, t, 1, yes, on (case-insensitive, trimmed). A JSON number is not truthy"enabled": 1 reads as false. Send a real boolean; the platform coerces what you send to one on write, so reading the agent back shows you what was actually stored.

Fields an app key may never write

Apps use PATCH /api/app-agents/{id}/config with per-group scopes rather than the fields above. Six are refused at every scope, on purpose:

FieldWhy
tools, precallLookupsThe agent's capabilities — what it can call, with which credentials
s2sConfigSelects the realtime engine and carries BYOK keys
isPublicThe governance decision that puts an agent on the open internet; it has its own owner/admin-gated route
createdByAppThe ownership stamp the whole app-agent plane scopes on
flowDraftAn unpublished working copy — writing it would let an app stage changes no reviewer sees

An app can edit the prompt of an existing node of any kind, but may only create nodes of kinds that talk rather than act: conversation, static, router, extract, dtmf, end, note. tool, code, transfer, agent and subagent nodes cannot be conjured by an app. Node config — a transfer node's destination number, a tool node's handler, a code node's source — stays read-only even on a node the app may otherwise retune.

See Bundled agents & teams for the app-key surface and its nine config groups.