Skip to main content
Contacts are the people an outbound agent reaches. Each contact belongs to one agent and holds a name, one or more phone numbers (or an email address for Email agents), an optional time zone, and a data object whose keys become script variables. This guide covers every contact operation in the API and the rules behind them.
Contacts can only be added to outbound agents. Inbound agents reject contact uploads with 400 Not allowed to create contacts on incoming campaigns.

Contact object

When you add a contact, you send:
string
required
The contact’s name. Available in scripts as {{name}}.
string
Primary phone number in international format, for example +14155552671. Required for Voice and Text agents unless you send phoneNumbers.
string[]
Several numbers for the same person. The first valid number becomes the primary number; the agent tries the numbers in order. Takes precedence over phoneNumber.
string
IANA time zone, such as Europe/London. If omitted, Callers detects it from the phone number. Used when the agent calls in the contact’s time zone.
object
required
Key/value pairs of strings that become script variables. Send {} if you have none. For Email agents, include email.
boolean
default:"false"
Create or update the contact as archived. Archived contacts aren’t called.
When you read contacts, each one includes id, name, phoneNumber, status, attempts, lastAttempt, createdAt, failedReason, failedReasonDetails, and both campaignId and agentId (the same value).

Add a single contact

POST /agents/{agentId}/contacts
Response
The single-contact endpoint is strict: if the contact can’t be saved (invalid number, missing required variable), it returns 400 with the reason, for example No contacts were added or modified. phoneNumber: Phone number is not valid: 225747466045.

Add contacts in bulk

POST /agents/{agentId}/contacts/bulk with { "contacts": [ ... ] }.
number
Contacts in the request.
number
New contacts created.
number
Existing contacts updated.
string[]
IDs of created or updated contacts. Returned when verbose is false (default).
object[]
Returned when verbose=true.
Bulk uploads are lenient about individual contacts: contacts with no name, no valid phone number, or missing required variables are skipped, and the rest are saved. Compare added + modified with requested to detect skips. Invalid data is the exception: if any contact’s data breaks the rules below, the whole request is rejected with 400. Request bodies are limited to 1 MB. Split large lists into batches and send them one after another.

Validation rules

Phone numbers

  • 7–20 characters: digits, (, ), -, optional leading +. Stored as digits only.
  • Must be a valid international number including the country code, unless the agent uses local dialing or you pass ignorePhoneNumberValidation=true (single contact only).
  • Duplicates within one contact’s phoneNumbers are ignored.

The data object

Values must be strings. Time zone keys inside data are ignored; use the top-level timezone field. Each validation problem appears in the error’s data array with a path (including the contact index for bulk) and a machine-readable params.code:

Duplicates and updates

Within an agent, a contact is identified by its primary phone number (for Email agents without a phone number, by its email address). When you add a contact that already exists:
  • name, data, phone numbers, time zone, and archived are replaced with what you send.
  • status, attempts, and call history are kept.
  • The response reports it as modified / updated.
This makes uploads safe to retry and lets you update a contact’s variables by re-sending it. Note that data is replaced, not merged: send every key you want to keep.
If the agent has Allow Duplicate Phone Numbers turned on, every upload creates new contacts and nothing is updated. That setting can’t be turned off once enabled. See Phone numbers and caller ID.

List and filter contacts

GET /agents/{agentId}/contacts Contact statuses: NEW, PENDING, PENDING_RETRY, SCHEDULED, IN_PROGRESS, COMPLETED, INTERESTED, NOT_INTERESTED, CALL_ME_LATER, DO_NOT_CALL, WRONG_NUMBER, VOICE_MAIL, UNREACHED, FAILED, SKIPPED. See Statuses and outcomes for what each means.
Use the [] suffix for list filters, even with a single value (statuses[]=INTERESTED). A plain statuses=INTERESTED is rejected as invalid.
Other read endpoints:

Calls across the agent

To reconcile outcomes without a contact ID, list calls for the whole agent and page through them:
Each call carries contactId, so you can join calls back to contacts. For the complete outcome of a call in the same shape your webhook receives, fetch /webhook-payload; see Backfill missed webhooks. The report for an outbound agent returns totalContacts, totalCallsCount, answeredCallsCount, and contactsByStatuses (a count for each status: NEW, PENDING_RETRY, SCHEDULED, IN_PROGRESS, FAILED, UNREACHED, NOT_INTERESTED, INTERESTED, COMPLETED, SKIPPED, CALL_ME_LATER, WRONG_NUMBER, DO_NOT_CALL). See Launch outbound calls for a full example.

Archive contacts

Archiving removes contacts from the calling queue but keeps them and their history. All archive endpoints accept an optional archiveReason. Bulk archive endpoints return { "archivedCount": n }.

Restore an archived contact

Add the contact again with the same phone number. Because uploads update existing contacts and archived defaults to false, the contact is restored with its history, and the archive reason is cleared.

Do Not Call

Archiving stops one agent from calling a contact. To make sure nobody in your account calls a number, add it to the account’s Do Not Call list in the dashboard. See Do Not Call.

Troubleshooting

The agent marks those variables as required. Add them to data, or make them optional in the agent’s variables settings.
The number lacks a country code or isn’t a real number for its country. Send + and the country code, or use fixUSPhoneNumber=true for 10-digit US numbers.
Use statuses[]=VALUE (with brackets), and check the values are uppercase status names.
The key in data must match the variable name exactly, including case. Keys with spaces are rejected; use first_name, not first name.

Launch outbound calls

The end-to-end outbound workflow.

Contact memory

Store facts the agent remembers across conversations.

Upload contacts in the dashboard

CSV import and manual entry.

Variables

How contact data reaches your script.