Skip to main content
Contacts are the audience a campaign dials. Each contact carries one or more phone numbers, arbitrary structured data, and optional per-contact overrides that change how its call is placed. You add contacts by uploading a CSV in the dashboard or by calling the contacts API directly.

What a contact holds

FieldTypeDescription
phone_numbersstring array (E.164)Ordered list of numbers to dial. Order is dial priority: the first number is tried first, then the next on retry.
dataJSON objectArbitrary key/value data. Any CSV column you do not map to a structured field lands here, and the whole object is passed as custom_metadata on the call so your agent and prompts can reference it.
external_idstringOptional identifier from your own system. Used as the upsert key and is unique per campaign.
timezonestringIANA timezone (for example America/New_York) used for call-window scheduling.
scheduled_atdatetimeISO 8601 time before which the contact is not dialed.
agent_id, agent_config, agent_number, agent_version, initial_contextoverridesPer-contact overrides of the campaign’s agent assignment, configuration, caller number, pinned version, and opening context. See Configurations for the campaign-level defaults these replace.
Structured fields (phone_numbers, external_id, timezone, scheduled_at, and the agent overrides) live as top-level columns. Everything else you send stays inside data. Do not duplicate a structured field inside data.

Upload a CSV

In the campaign, open the contacts uploader and drag a CSV onto the drop zone (or click to browse). The uploader parses the file in the browser, auto-detects columns, and lets you adjust the mapping before sending.
1

Drop the file

Drag a .csv file onto the upload area. The file must be 10MB or smaller, and at most the first 1000 rows are read.
2

Confirm the mapping

The uploader auto-detects phone columns by header name (for example phone, phone_number, mobile, cell, tel) and maps Contact ID, External ID, Timezone, and Scheduled At when it recognizes their headers. Adjust any mapping that is wrong.
3

Review and upload

Mapped timezones, datetimes, and contact IDs are validated inline. Unmapped columns are kept in data. Submit to send the batch.
The CSV uploader maps only the structured fields above plus phone columns. Per-contact agent_config and initial_context overrides are API-only — set them through the contacts endpoint.
The uploader maps a column named id (or contact_id, anyreach_id) to the Anyreach Contact ID, which must be a UUID and updates an existing contact in place. To match against your own keys instead, map your column to External ID.

Add contacts via the API

curl -X POST https://api.anyreach.ai/campaign/campaigns/{campaign_id}/contacts \
  -H "Authorization: Bearer <token>" \
  -H "X-Anyreach-Org: <organization_id>" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      {
        "external_id": "crm-4821",
        "phone_numbers": ["+14155550101", "+14155550102"],
        "timezone": "America/Los_Angeles",
        "scheduled_at": "2026-07-01T17:00:00Z",
        "initial_context": "Renewal due next week.",
        "data": { "first_name": "Dana", "plan": "pro" }
      }
    ]
  }'
POST /campaign/campaigns/{campaign_id}/contacts upserts the batch. For each contact it matches an existing row by id first, then by external_id within the campaign, and updates it; otherwise it inserts a new contact.
LimitValue
Contacts per API request1000
Contacts inline on campaign create or update5000
CSV file size10MB
CSV rows read1000
Sending contacts inline when you create or update a campaign accepts up to 5000 in a single payload; the standalone contacts endpoint accepts up to 1000 per call.

Phone normalization

Numbers are normalized to E.164 using the campaign configuration’s default_country_code, so you can upload local-format numbers as long as they belong to that country. A number that cannot be parsed into a valid E.164 number fails the whole request with 422; the response lists the first invalid numbers.
Adding contacts to a campaign whose status is closed returns 400. Reopen or recreate the campaign before uploading.

Contact statuses

As a campaign runs, each contact moves through these statuses:
StatusMeaning
pendingEligible to be dialed and waiting in the queue.
lockedReserved by a worker and about to be dialed.
in_progressA call attempt is currently active.
completedThe contact reached a terminal successful outcome.
exhaustedAll retry attempts were used without success.
errorProcessing failed in a way that stopped further attempts.
Track these and per-contact attempt outcomes from Results and analytics.

Configurations

Set the agent, caller number, country code, retries, and call window a campaign applies by default.

Results and analytics

Review attempts, outcomes, and assessment results per contact.