Campaign Service
Add or Create Contacts in Campaign
Request Body
Each contact in the
contacts array should have the following fields:
Note: A contact already enrolled in the campaign is not enrolled again, and a
re-add never schedules a second call. If you re-submit an already-enrolled
contact in the
contacts array with new variables, those variables are
refreshed on the existing enrollment, and custom_fields on a matched contact
are merged and updated. Only the enrollment (and any pending call) is left
untouched.
Duplicate phone numbers
By default (allow_duplicate_phone omitted or false), a contacts entry
whose phone number already exists in your workspace does not create a
second contact. The most recently created matching contact is reused (its
custom_fields/variables are refreshed) and enrolled. If more than one
existing contact shares that phone, the newest is chosen and a
multiple_matches entry is added to the response contact_warnings array.
This default protects against a retried request creating duplicate contacts
and placing duplicate calls.
Set allow_duplicate_phone: true when you genuinely want a new, distinct
contact even though the phone already exists (the platform allows multiple
contacts to share a number, the same as the app UI). With it enabled, every
contacts entry is created as a new contact and enrolled, and its
id appears in added_contact_ids.
- The flag only affects the
contactsarray.contact_idsare unaffected. - When enabled, no phone matching happens, so no
multiple_matchesentry is ever added tocontact_warnings. - Caution: because each request creates new contacts, retrying the same
request with
allow_duplicate_phone: truecreates additional contacts and places additional calls. Use it only for genuinely distinct people, and do not use it as a blind retry. - If the value is not a boolean, the request fails with a
400.
added_contact_ids, and there is no
contact_warnings entry even though the phone was already in use.
Variables and prompt personalization
Campaign calls support the same{{var.KEY}} prompt substitution as the
direct call endpoint. Per-contact variables
(inside a contacts entry) are stored on the campaign enrollment and
injected into every call the campaign places to that contact — including
calls deferred by quiet hours and later steps of a multi-step campaign. They
are not used for SMS steps.
Variables are only accepted on contacts entries. Contacts enrolled via
contact_ids carry no variables — to attach variables to an existing
contact’s calls, set values on the contact’s custom_fields instead (those
render as {{custom.<key>}} and apply to every call with the contact).
Constraints (same as the call endpoint): at most 50 keys, keys must match
^[a-zA-Z][a-zA-Z0-9_]{0,62}$, values up to 1000 characters, whole object
under 4KB serialized. Violations fail the request with a 400.
In your agent prompt or greeting, reference variables as {{var.KEY}}:
Hi {{var.lead_name}}, this is about your {{var.product}} appointment on {{var.appt_time}}.
Custom fields
custom_fields values are validated against the field definitions configured
in your workspace (Portal → Contacts → Custom Fields) and stored on the
contact itself. Stored values can be referenced in agent prompts and
greetings as {{custom.<key>}} — on every call with that contact, not just
campaign calls.
Validation is drop-and-report: keys that are not defined in your
workspace, archived, or reserved — and values that fail the field’s type
validation — are dropped while the contact is still created and enrolled.
Every dropped entry is reported in the custom_field_warnings array of the
response, with the contact’s index and phone for correlation. Warning codes:
unknown_key, archived_key, reserved_key, type_mismatch,
option_invalid, too_long, empty_value.
Custom fields vs variables:
Example Request
{{var.appt_time}} and
{{var.quote_amount}} in the agent prompt; the existing contact enrolled by
ID gets no variables.
Response
custom_field_warnings is present only when at least one custom_fields entry
was dropped.