Reference

Variable substitution

Dynamic placeholder syntax for injecting runtime values into templates.

Overview

Variable substitution allows templates to reference dynamic values using {'{placeholder}'} syntax. At call time, placeholders are resolved from multiple sources and injected into messages, URLs, headers, and request bodies.

Template with {placeholders}
Lead payload received
Resolve variables (payload → secrets → credentials)
Substituted template
Conversation starts

Syntax

Variables use single curly braces: {'{variable_name}'}. Names are case-sensitive and must match a key in one of the resolution sources.

Resolution order

The three sources are merged sequentially — last writer wins. In practice that means lead-payload values always override template secrets, which always override credential secrets. The same ordering in priority terms:

PrioritySourceExample KeysDescription
1 (highest)Lead Payloadcustomer_name, appointment_datePer-call data pushed when creating the lead
2Template Secretsapi_token, webhook_urlDefined in the template’s secrets object
3 (lowest)Credential Secretsapi_secret, auth_keyMerchant-level credentials shared across templates

Last-writer-wins via merge

Internally all three dicts are merged in order credentials → secrets → payload. Later writes overwrite earlier ones, so payload fields always win. This also means a duplicate key between credentials and secrets silently resolves to the secret — credentials cannot shadow secrets.

Variable sources

Lead Payload

Per-call data pushed via the API:

POST /agent/voice/breeze-buddy/leads
lead-payload.json
json
{
  "template_id": "abc-123",
  "payload": {
    "customer_name": "Priya Sharma",
    "appointment_date": "2026-04-15",
    "appointment_time": "10:30 AM",
    "doctor_name": "Dr. Mehta",
    "clinic_phone": "+91-9876543210"
  }
}

Template Secrets

Secrets shared across all calls on this template:

template-secrets.json
json
{
  "secrets": {
    "api_token": "sk-live-abc123xyz",
    "webhook_url": "https://hooks.example.com/breeze"
  }
}

Credential Secrets

Merchant-level credentials (lowest priority fallback):

credential-secrets.json
json
{
  "api_secret": "sk-merchant-global-key",
  "auth_key": "merchant-auth-abc"
}

Where variables work

LocationExample
task_messages content"You are calling {customer_name} about order {order_id}"
role_messages content"Address the customer as {customer_name}"
pre_actions tts_say text"Hello {customer_name}, thank you for your patience."
HTTP request url"https://api.example.com/orders/{order_id}"
HTTP request headers"Authorization": "Bearer {api_secret}"
HTTP request body"customer_id": "{customer_id}"
Hook field values (static){ "source": "static", "value": "{campaign_id}" }
Global function pre_tts_message"Looking up your order, {customer_name}"

Variables in task messages

dynamic-task-message.json
json
{
  "task_messages": [
    {
      "role": "system",
      "content": "You are calling {customer_name} to remind them about their appointment with {doctor_name} on {appointment_date} at {appointment_time}."
    }
  ]
}

At call time, this resolves to:

resolved-task-message.json
json
{
  "task_messages": [
    {
      "role": "system",
      "content": "You are calling Priya Sharma to remind them about their appointment with Dr. Mehta on 2026-04-15 at 10:30 AM."
    }
  ]
}

Variables in HTTP requests

Note the difference between {'{variable}'} (template variable) and <<field>> (hook field reference):

http-with-variables.json
json
{
  "http_request": {
    "url": "{webhook_url}/appointments",
    "method": "POST",
    "headers": {
      "Authorization": "{callback_auth}",
      "Content-Type": "application/json"
    },
    "body": {
      "name": "{customer_name}",
      "date": "{appointment_date}",
      "status": "confirmed"
    }
  }
}

Built-in & computed variables

The system provides computed values through the computed field source in hooks:

ExpressionDescriptionExample Output
utc_nowCurrent UTC timestamp2026-04-15T10:30:00Z
utc_now_minus_hours:0Current UTC timestamp (equivalent to utc_now)2026-04-15T10:30:00Z
utc_now_minus_hours:1UTC minus 1 hour2026-04-15T09:30:00Z
utc_now_minus_hours:24UTC minus 24 hours2026-04-14T10:30:00Z
ist_nowCurrent IST (UTC+5:30) timestamp2026-04-15T16:00:00+05:30
utc_today_startStart of today in UTC (00:00:00Z)2026-04-15T00:00:00Z
utc_today_endEnd of today in UTC (23:59:59Z)2026-04-15T23:59:59Z

Payload transformations

expected_payload_schema entries can carry a function key that transforms the payload value before injection. Single transforms use a string; chains use a list (applied left to right).

payload-transform.json
json
{
  "expected_payload_schema": {
    "type": "object",
    "properties": {
      "customer_name": { "type": "string", "function": "string_trim" },
      "order_id": {
        "type": "string",
        "function": ["string_trim", "string_to_uppercase"]
      },
      "phone_number": { "type": "string", "function": "extract_10_digit_mobile" }
    }
  }
}

Registered transformation functions:

FunctionDescription
string_trimStrip leading/trailing whitespace.
string_to_lowercaseLowercase the string.
string_to_uppercaseUppercase the string.
indian_number_to_speechRender Indian-format numbers as spoken words.
digits_to_speechRender a digit string as spoken digits.
date_to_speechRender an ISO date as spoken English.
extract_10_digit_mobileExtract the trailing 10-digit mobile number from a longer string.
expand_shorthandExpand common shorthand (e.g. “Dr” → “Doctor”).

Payload validation

Use expected_payload_schema to validate required variables are present:

payload-schema.json
json
{
  "expected_payload_schema": {
    "type": "object",
    "properties": {
      "customer_name": { "type": "string" },
      "appointment_date": { "type": "string" },
      "doctor_name": { "type": "string" }
    },
    "required": ["customer_name", "appointment_date", "doctor_name"]
  }
}

Two different failure modes

A placeholder for a key outside expected_payload_schema stays as literal text (e.g. {unknown_var}). But a placeholder for a schema-declared field that the lead payload didn’t include resolves to the empty string "" — which can silently corrupt prompts (“Hello , your order is ready”). Always send values for every schema-declared field.

Escaping & edge cases

No Escape Syntax

There is currently no escape syntax for literal curly braces. Use distinctive variable names to prevent accidental resolution.

  • Case sensitivity: {'{Customer_Name}'} and {'{customer_name}'} are different
  • Missing variables: Placeholder remains as literal text
  • Empty values: Replaced with empty string (not removed)
  • Nested resolution: Not recursive — resolved values containing {'{placeholders}'} are not resolved again
  • JSON values: Variables always resolve to strings

Best practices

  • Use expected_payload_schema to validate required variables
  • Keep sensitive values in template secrets or credential secrets — never in the lead payload
  • Use descriptive names: {'{customer_name}'} over {'{name}'}
  • Test substitution by reviewing resolved templates in logs
  • Document your payload schema for API consumers
Was this helpful?