Open in
Per-call variables and context
Give each call its own details, as named variables for the prompt or a free-form brief, without changing the agent.
Each call can carry two kinds of per-call input. Use either one, or both together:
variables: named values that fill{{placeholders}}in the prompt. Use them for fields the prompt refers to by name, such as the caller's name, an account number or an appointment slot.context: free-form text added after the prompt. Use it for a brief that does not fit a template, such as a description of the task for this call or notes collected earlier.
Both work with a saved agent and with an inline configuration, on every way of starting a call described below. Neither changes the saved agent, its version history or its other settings.
{
"agent_id": 12,
"variables": {"name": "Ada", "appointment_slot": "Tuesday at 10 AM"},
"context": "Ada rescheduled twice last month. She prefers mornings and asked us not to call her work number."
}Variables
Put placeholders in your saved agent's prompt, then supply a variables
object when starting a call. ThunderPhone renders the text before sending the
call configuration to the voice runtime.
When no values are needed, omit variables, do not send null (rejected with 400).
Placeholders and defaults
You are calling {{name|Friend}} about account {{account_id}}.
The available appointment is {{ appointment_slot }}.Names are case-sensitive and follow [A-Za-z_][A-Za-z0-9_]*. Whitespace around
the name is allowed; whitespace after | is part of the default and is
preserved. {{name|Friend}} uses Friend when name is missing or
null; an empty string is an explicitly supplied value. Missing values without
a default become empty strings and their names appear in unresolved_variables.
Text between double braces that is not a valid placeholder is removed. Double-braced
text inside each supplied value is removed independently; a value cannot remove
surrounding prompt text or another value. Unmatched double-brace delimiters are
removed too. JSON examples in prompts must not use {{.
Values are plain text, never evaluated
as code or recursively expanded as templates.
Variables can also appear in acknowledgement prompts, outbound voicemail
messages, and the consent announcement text when that field is sent for a
phone call. The agent has no separate first_message field: put its opening
instructions in the prompt. Existing voicemail {agent_name} and {org_name}
placeholders continue to work.
Values and limits
Values may be strings, numbers, booleans, or null; booleans render as true
and false. Unicode control (Cc) characters except newline (\n), tab (\t),
and carriage return (\r), format (Cf) characters except the zero-width
non-joiner and joiner (U+200C, U+200D, which spell words in Indic and
Arabic-script languages), and surrogate (Cs) code points are removed; \r\n
is normalized to \n. Each value
is limited to 2,000 characters when rendered. Supplied strings are cleaned and
truncated before storage as well. The original object must fit in 32 KB of
UTF-8 JSON; larger objects receive 400 on call/session requests, while
campaign imports report invalid rows individually. Arrays and nested objects are not
accepted as values. Nonmatching metadata keys (for example a CSV header with a
space) are retained and echoed but cannot be referenced by a placeholder.
Context
context is a string of up to 20,000 characters. ThunderPhone adds it after
the prompt, once the prompt's variables are filled in, as a delimited block:
<your prompt, with its variables filled in>
Details for this call:
<call_context>
Ada rescheduled twice last month. She prefers mornings and asked us not to call her work number.
</call_context>The agent reads it together with its instructions, so write it the way you
would brief a colleague before the call. Context is not a template:
{{name}} inside it stays as written. If the text needs a value, put the value
in yourself before sending.
null, an empty string, or only whitespace means no context.- A value that is not a string, or is longer than 20,000 characters, is
rejected with
400on call and session requests; from a configuration webhook it fails the exchange like invalidvariables(see below). - Leading and trailing whitespace is trimmed, and the same control and format characters as in variable values are removed.
- Context is part of the call's prompt, so it counts toward the call's prompt size.
On a steps agent, the context follows the prompt of every agent in the call, not each step's instructions.
Where values come from
Outbound API
Send variables and context on POST /v1/call:
{
"from_number": "+15551234567",
"to_number": "+14155552671",
"agent_id": 12,
"variables": {
"name": "Ada",
"account_id": "A-17",
"appointment_slot": "Tuesday at 10 AM"
},
"context": "Ada asked to be called back about the late fee on her March invoice."
}Both also work with the phone number's default outbound agent, or with an inline
config.prompt. With an inline config, context can also go inside config,
the same field a configuration webhook returns; if you send both, they must be
the same text. An idempotency key cannot be reused with different variables or
a different context.
Campaign CSV
Non-phone CSV columns are already stored as contact variables. Each dial now
uses them automatically. Use headers such as name, account_id, and
appointment_slot to match your placeholders. The existing name mapping can
combine first and last name columns into the variable name. Campaign
contacts have no per-contact context.
Dynamic configuration webhook
On the blocking configuration webhook path, return a saved agent in your organization plus any per-call values:
{
"agent_id": 12,
"variables": {"name": "Ada", "account_id": "A-17"},
"context": "Ada called yesterday about a leak in unit 4B; a plumber is booked for Friday."
}The response's variables overwrite request-level variables, while other request
keys remain. A response value of null selects the placeholder's default.
The merged object must also fit in 32 KB. Saved-agent responses accept only
agent_id, variables, context and a per-call
timezone; return an inline configuration when you need to
replace the prompt or other settings. A response containing prompt always uses inline
configuration: any agent_id in that response is ignored, including null or
non-integer metadata. The inline prompt still must pass normal validation.
Inline webhook responses can include variables and context too. A context
that is not a string or is too long fails the exchange: a phone call is
rejected, and a widget session request fails with 400. Saved-agent webhook
responses use the agent's deployed A/B split on both phone and widget calls;
variables render after variant selection. On inbound phone calls, use a number with no assigned inbound
agent and configure its phone-number or organization webhook; widget keys use
mode="webhook". Endpoint-system incoming notifications do not supply blocking
configuration responses.
Agent call setup webhook
To keep a number assigned to its agent and fill in only the call's values,
give the agent a call setup webhook.
Before each inbound call the agent answers on a number, the webhook gets the
call and the agent's id, name and version, and answers with the same
variables and context as above, without needing an agent_id. An agent
whose settings use a placeholder with no default needs this webhook to answer
a phone number: the call does not start when the webhook fails. Placeholders
with a default, like {{name|there}}, let the agent answer without it.
SIP headers
Calls that reach an agent over SIP (a SIP address, or
a number on a manual SIP connection) can carry context in X-* and
User-to-User headers. Each one becomes a sip_ variable, such as
{{sip_x_amzn_connectcontactid}} or {{sip_uui}}, with the lowest
precedence: a value of the same name from the API or a webhook wins. See
Pass call context in SIP headers.
Header values are set by the sender, so treat them as untrusted, like any
browser-supplied value.
Widget session API
POST /v1/widget/session accepts a top-level variables object. Its publishable
key selects the saved agent. Webhook-mode keys forward these values to the
configuration webhook and merge the response as described above.
Browser-supplied widget variables are client-controlled, forwarded
verbatim in web.incoming after the validation and string cleanup described
above, and echoed into completion webhooks and call history. Do not treat them
as trusted identity or authorization data.
The widget's own browser context field is different: it carries text from the
page the visitor is on, which the agent treats as website content (see
Embed the web widget). A widget call's per-call
context comes from a webhook-mode key's configuration webhook, as above. When a
call has both, the per-call context comes first, then the page content.
Realtime session API
POST /v1/realtime/sessions accepts top-level variables and context
alongside agent_id or an inline config:
{
"agent_id": 12,
"variables": {"name": "Ada"},
"context": "Ada is calling from the front desk about a guest's lost key card."
}context goes at the top level only; an inline config rejects it as an
unknown field.
Realtime WebSocket
With a saved agent, the saved agent's deployed prompt stays its prompt.
session.instructions becomes the call's context, and session.prompt.variables
(or session.config.variables) become its variables. Choose the agent with
session.prompt.id in the first session.update, which starts the session once
that update arrives:
{
"type": "session.update",
"session": {
"type": "realtime",
"prompt": {"id": "12", "variables": {"name": "Ada"}},
"instructions": "Ada asked for a callback about her delivery window."
}
}?agent_id=12 on the connection URL starts the agent as soon as the socket
connects, before any session.update, so it carries no per-call input. Add
&wait_for_session_update=1 to wait for the first session.update and use its
instructions and variables.
In an inline session (no saved agent), session.instructions is the prompt
itself, as before. Builder mic and simulated test calls resolve defaults and
missing placeholders but have no per-call variables or context input.
After the call
GET /v1/calls, GET /v1/calls/{call_id}, telephony.complete, and web.complete include the
final merged variables and unresolved_variables. Legacy completion payloads
that include data.history include them too:
{
"variables": {"name": "Ada", "account_id": "A-17"},
"unresolved_variables": ["appointment_slot"]
}The call's prompt_snapshot (GET /v1/calls/{call_id}) shows the agent's
prompt with its variables filled in and the context block added.
Store your CRM or task identifier in the variables object to join the completed call back to its source record. Variables and context are retained with the call record; only send information appropriate to retain in call history and webhooks.
Replays of a call, in validation sets, replay runs and investigations, use that call's variables and context with the prompt under test, so a replay tests what the agent on that call would have been told.
Existing prompt compatibility
Rendering also applies to existing saved-agent and A/B variant prompts, inline
outbound and realtime configurations, and prompts returned by configuration
webhooks. Unknown {{name}} placeholders become blank text, even when no
variables are supplied. Check existing prompts before rollout, including
externally supplied inline/webhook prompts that ThunderPhone cannot inventory.
Builder mic and simulation calls apply the same default/blank behavior.