Skip to main content
Write a variable in double braces, {{first_name}}, in any line the agent says: the system prompt, the first message, the end-call and silence messages, the voicemail message, the built-in tools’ spoken lines and each disclosure. Names use letters, digits, _ and ., and spaces inside the braces are ignored, so {{ first_name }} is the same token. Single braces are left alone, so JSON examples in a prompt stay as written. Every name in Vodex is snake_case: contact fields, custom fields, caller verification sources and the examples on this page. Use the same spelling in your prompts, your CSV headers and your API requests and they will line up everywhere.
A token with no value is said as written. The agent reads out Hi {{first_name}} with the braces, which is why campaigns and batches refuse a contact or row that is missing one rather than calling with a gap. A call placed through POST /calls is not refused, so check your variables there.

Contact fields

A contact fills these on its own. In a campaign or a Call now from the contact’s page, {{first_name}} needs no mapping. The Contact details tab shows each token beside its field. The API field column is the name the REST API uses for the same value, in request bodies and as a campaign source (field:firstName). It stays camelCase like the rest of the API. Only the token is snake_case. The contact import template uses the tokens as its column headers, so a file built from it, a prompt and the Contact details tab all use the same names. A value is only fetched when the prompt (or caller verification) asks for it, so a script that never mentions {{ssn_last4}} never puts it into a call.

Other spellings

Contact field tokens ignore case and punctuation, so {{firstName}}, {{First_Name}} and {{first_name}} all fill from First name. Prompts written before snake_case became the documented spelling keep working. They also answer to the words a CSV header uses for the same field: {{name}}, {{surname}}, {{zip}}, {{postcode}}, {{dob}}, {{ssn}}, {{street}}, {{town}}, {{province}}, {{tz}}, {{phone_number}}. A few words are deliberately not recognised, because each one could mean several things in a sentence: {{number}}, {{account}}, {{reference}}, {{ref}}, {{unit}}, {{apt}}, {{suite}}, {{region}}, {{county}}. A labelled number such as {{mobile}} or {{work_phone}} is not recognised either, since the call may be dialling a different one. Use {{phone}}.
This forgiving match applies only to contact fields. Variables in an API request and columns in a batch CSV are matched by their exact name: a CSV column called first_name fills {{first_name}} and nothing else.

Fields that never fill themselves

External id, Status, Notes, Tags, the assigned user, the do-not-contact fields, consent, the created and updated times, and the last-contacted fields are not tokens. They are ids, workflow state or notes written about the contact, not things to say to them. A campaign can still map one explicitly, for example "stage": "field:status".

Custom fields

A custom field is {{key}}, where the key is the one shown under the field on the Custom details tab: attr:renewal_date is {{renewal_date}}. Keys are made from the label when the field is created, so “Renewal Date” becomes renewal_date, already in snake_case. Custom fields fill on their own in the same places contact fields do, and match ignoring case and punctuation in the same way. When a custom field and a contact field share a name, the custom field wins whenever it has a value: a city custom field fills {{city}} instead of the City column. The Contact details tab warns beside any field this happens to for that contact. A checkbox is said as “yes” or “no”, and a list as its items joined by commas.

How each way of calling fills them

Campaigns

At launch, each contact’s variables are built in this order, each layer over the one before:
  1. Their contact fields, for every token the prompt says.
  2. Their custom fields.
  3. The campaign’s variables map.
  4. tz, set from the contact’s time zone. The calling window reads it.
The map is only needed for a name the contact does not already answer to. Each entry says where the value comes from:
A name in the map uses only its mapping. If the mapped source is empty for a contact, that contact is rejected at launch. Vodex does not fall back to a field of the same name. The sources a campaign can map are listed by the API, along with the tokens a contact fills on its own.

Call now from a contact

The contact’s fields and custom fields fill the prompt the same way, with nothing to map. A token they have no value for is said as written.

POST /calls

Set contactRef to a contact’s id and any variable the request leaves blank is filled from that contact. The order, highest first:
  1. The request’s variables. Blank values are ignored.
  2. The contact named by contactRef: custom fields, then contact fields.
  3. The agent’s saved default values.
With the prompt Hi {{first_name}}, your balance is {{balance}}, the name comes from the contact and the balance from the request. Request variables match by exact name, so send first_name, not firstName.

Batches

Every CSV column except to, rowRef, assistantId and from becomes a variable named exactly as its header, so a first_name column fills {{first_name}}. A row missing a variable the prompt says is refused at upload. Batches do not read your contacts. Add a tz column for calling windows.

Test calls from the agent page

Values typed beside each variable on the agent page are saved with the agent as its defaults. Test calls from that page use them. On real calls they are the last fallback, below the request and the contact, and they never count for a campaign or batch row, which must carry its own values. They are never used for caller verification answers.

Caller verification

Each verification question names the variable that holds the right answer, its Answer comes from. On a campaign or a contactRef call that variable is filled from the contact like any other, so date_of_birth checks against the contact’s date of birth and full_name against their name. On a batch it is a CSV column, and on an API call a request variable. The answers are kept out of the call: a question’s source cannot also appear as a {{token}} in the prompt, under its own name or any other spelling of the same field ({{zip}} for a postal_code answer), and the answers are left off the call record and the webhook. The one exception is the name used for confirmation, which the agent has to say. Write it as {{full_name}}. {{address}} leaves out any part that is a question’s answer, so verifying on postal_code gives 88 Union Ave, Floor 2, Memphis, TN, US. When the answer is already written into the address itself, in line 1, line 2 or a custom address field, {{address}} is left out altogether. When the question is the address itself, its answer is the two street lines, which is what a caller says back, and {{address_line1}}, {{street}} and {{address_line2}} are kept out of the prompt as well.

SMS and email templates

In-call SMS and email templates use the same variables as the call. They accept {first_name} as well as {{first_name}}, ignore case, and drop a token with no value instead of sending the braces. When two variables differ only in case, the one spelled exactly as the token wins. {{full_name}} and expressions such as {{ amount + 25 }} are worked out the same way as in the prompt. Dates such as {{today}} use the same timezone the call’s prompt does, the contact’s tz or the batch’s calling window; with no timezone at all a template leaves the date out rather than send the UTC one. A template only has the variables the call already has, so a contact field mentioned only in the template, never in the prompt, is blank.

Next

Contacts

Importing people, audiences, and launching a campaign.

Place a call

variables and contactRef on a single call.