VoiceCampaigns

Adding Recipients

Who a campaign calls: upload a CSV to a one-shot campaign, or feed a continuous campaign over the REST API, with Copilot or MCP, or from Python with add_campaign_recipients. Covers recipient fields (phone, name, context, metadata, dedupeKey, isTest), E.164 validation, limits and de-duplication.

A recipient is one person a campaign calls. How you add recipients depends on the mode:

ModeHow recipients are added
One-shotOnce, when the campaign is created: a CSV upload in the dashboard, or recipients on create_campaign.
ContinuousAt any time while it's a draft, running or paused: REST API, Copilot or MCP, or Python.

Recipients can't be removed one by one. To stop calling someone, skip them in a Pre-Call hook.

Recipient fields

FieldWhat it's forLimit
phoneThe number to call, in E.164 format with a leading +, such as +15551234567. Spaces, dots, dashes and brackets are removed; anything else makes it invalid.Required
nameSpoken in the greeting through {name}, and used as the customer's name in the help desk.500 characters
contextFree text the AI reads before the call, such as "Ordered a blue sofa on 2 May, delivery pending". See what the AI knows.2,000 characters
metadataA JSON object for your own code: hooks and Python actions see it. The AI never sees it.4 KB as JSON
dedupeKeyYour own ID for this call, such as an order number. See De-duplication.1-200 characters
isTestA test recipient: called normally, left out of the metrics.true or false

Use context for anything the AI should say or know, and metadata for IDs your hooks need, such as a customer or order ID.

Upload a CSV

On Create Campaign, choose One-shot, then upload a CSV file under Upload Recipients. Download the template gives you the format:

phone,name (optional),context (optional)
+15551234567,Jane,Ordered a blue sofa on 2 May
  • phone is required; name and context are optional. Column names are case-insensitive, and the "(optional)" suffix may be left out.
  • Other columns are ignored. A CSV can't set metadata, dedupeKey or isTest.
  • If any row has an invalid phone number or a too-long value, the whole file is rejected with the number of bad rows. Fix them and upload again.
  • Duplicate phone numbers are dropped.
  • Up to 10,000 recipients and 10 MB per file. Split bigger lists across campaigns.

Feed a continuous campaign

REST API

curl -X POST "https://api.octocom.ai/rest/v1/campaigns/<campaignId>/recipients" \
  -H "X-API-Key: <organization API key>" \
  -H "Content-Type: application/json" \
  -d '{"recipients": [{"phone": "+15551234567", "name": "Jane", "context": "Abandoned a cart with a blue sofa", "metadata": {"cartId": "c_123"}, "dedupeKey": "cart-c_123"}]}'

The response is {"added": 1, "skippedDuplicates": 0}. Up to 10,000 recipients per request. The campaign's Configure page shows its exact endpoint and an example under Feed recipients via API. See the REST API for authentication.

The request returns once the recipients are queued. They're called as soon as the campaign is running, within its calling hours.

Python

From a recurring job, event handler or custom action, use add_campaign_recipients:

result = add_campaign_recipients(
    "<campaignId>",
    [{"phone": "+15551234567", "name": "Jane", "dedupeKey": "cart-c_123"}],
)
# {"added": 1, "skippedDuplicates": 0}

A typical setup is a recurring job that finds customers to call, such as abandoned carts from the last hour, and adds them.

Copilot or MCP

Use append_campaign_recipients. It returns how many were requested, added and skipped as duplicates.

Errors

Adding recipients fails when the campaign is one-shot, completed or canceled, or when a phone number isn't valid E.164.

De-duplication

  • Within one request, only the first recipient per phone number and per dedupeKey is kept.
  • A phone number already waiting or being called in the campaign is skipped.
  • A phone number whose earlier call is finished can be added again. A continuous campaign can call the same person again later.
  • A dedupeKey is used once per campaign, forever, even after its call finished. Use it to make sure the same event never causes two calls, for example cart-<cartId>. To call someone again for a new reason, use a new key.

Skipped recipients are counted in skippedDuplicates. Different campaigns don't de-duplicate against each other.

On this page