{{name}} placeholders in the configuration and they are substituted once, when the published configuration is assembled for the session. There are two kinds:
- Custom variables: values you supply when you create the session, such as the caller’s name or plan.
- System variables: facts about the session itself, such as the caller’s phone number or the date, filled in by the platform under the reserved
system.*names.
Where variables render
Placeholders are substituted in the agent’s configured text and in webhook tool requests. Everything else (knowledge base content, tool names and descriptions, post-call analysis prompts) is left as written.
Custom values travel with the request that starts the session:
dynamic_variables on POST /v1/agent/sessions, dynamicVariables in the SDK’s AgentSession.start() for public agents, dynamic_variables on POST /v1/agent/phone-calls for outbound calls, and the variables panel of a preview call in the Builder. Inbound phone calls have no such request: values come from the inbound call webhook on the agent’s Webhooks tab when one is configured; the caller’s number and the other session facts are always available as system variables.
Custom variables
Write{{variable_name}} placeholders in your agent’s system prompt or first message and supply values when you create the session:
System prompt
[A-Za-z][A-Za-z0-9_]* (no hyphens or dots; the dotted system.* names are reserved for system variables), string values are capped at 1,000 characters, and a request can carry at most 50 variables. Violations reject session creation with 422:
{{placeholders}} render inside overridden text too.
Who supplies the values
Where custom variable values come from depends on the session’s access mode:
In
sessionToken mode the SDK’s dynamicVariables option has no effect. The session already exists by the time the token reaches the browser. Attach personalization server-side instead:
Backend (sessionToken mode)
System variables
The platform fills a handful of{{system.*}} placeholders itself, on every session. You cannot supply or override them: the names you pass in dynamic_variables cannot contain a dot, so the two namespaces never collide.
Phone numbers
The phone numbers are the session’scaller_number and dialed_number fields as shown in session history. Only a value that is a well-formed E.164 number reaches the agent: anything else the carrier sends as the caller id (for example an anonymous marker) renders as an empty string, while the history field keeps the raw value. On every session that is not a phone call (web, text, preview, agent tests) both render as an empty string, never as literal {{system.caller_number}} text, so one agent can serve web and phone with the same prompt.
Write the prompt so it also reads well when the number is empty:
System prompt
Rendered
The caller's number is ""., and the agent asks for a number. To look the caller up in your own systems, template the number into a webhook tool instead of relying on the model to repeat it.
Date and timezone
system.today is always ISO formatted, whatever the session language: in the system prompt the model reads it and speaks it in the session’s language, while a fixed first message containing {{system.today}} is spoken verbatim as 2026-08-21. A session that runs past midnight keeps its opening date. Template it, and system.timezone, when a request needs them explicitly, for example a webhook tool’s query string; for the agent’s own sense of time no variable is needed, see World context.
In webhook tools
System variables render wherever custom variables do, and also inside webhook tool requests: the URL, header values, and body template. Custom variables do not render into tools. In the URL the value is URL-encoded, like argument values: the leading+ of an E.164 number travels as %2B and the / in a timezone name as %2F, both decoding back on your server.
Webhook tool URL
Unknown names
A reference to a system variable that does not exist ({{system.foo}}) is rejected with 422 when you save the configuration or the tool, and when you send it in session overrides. The error lists the available names.
World context
The agent knows the current date and time without any variable. The platform states the date and the session’s timezone at the start of every session and refreshes the time on every turn, so “tomorrow morning” or “next Tuesday” resolve correctly even in a long conversation. You don’t need a custom{{today}} or {{now}}, and there is no system.now: variables render once, when the session is created, so a templated time would be stale from the first reply onward. When you want the date or timezone as text in a template, for example in a webhook tool URL, use the system.today and system.timezone system variables.
See Time & timezone for how the timezone is resolved and how to turn the injection off for a session (world_context: false).
Going further
Agent configuration
The fields your placeholders act on.
Overrides
Replace whole configuration fields for one session.
Versions & publishing
Sessions assemble the published configuration.
Web SDK
Every
AgentSession.start() option.
