Skip to main content

Overview

A campaign calls a list of phone numbers with one agent. You give it an agent, a phone line, and a CSV file of recipients. The campaign places calls, up to its concurrency limit. Each call uses the agent’s script. The values in the CSV fill the agent’s {{variables}}, so each call can use the recipient’s name or other details. Each call goes through the same checks as any other call: AI credits, the Dialer balance on a 60db line, and the workspace call limit. A campaign pauses when one of these checks stops it. See Statuses and pause reasons. You can manage campaigns in the dashboard at /app/agents/campaigns, or with the API. The API reference starts at List campaigns.

Before you start

Only call numbers whose owners agreed to be called. Add the others to the do-not-call list.

CSV format

The first row is the header. The file needs one phone column.
Phone column. The header must be one of phone, phone_number, number or mobile. Case, spaces and punctuation are ignored, so Phone Number also works. If a file has more than one of these, the first match in this list is used. Phone numbers. Use an international number, with + or 00 in front, such as +919876543210. A number without + or 00 uses the phone line’s default country code. A number that cannot be made international is skipped with the reason invalid_number. Other columns become variables. Every other column becomes a variable. Its key is made from the header: lowercase letters, digits and _. For example, customer name becomes customer_name. If two headers give the same key, the first column is used. A value is kept up to 500 characters. A row whose variables are larger than 4 KB is skipped with the reason variables_too_large. File rules. A file over a limit, or a file the parser cannot read, is refused with CAMPAIGN_INVALID. Check the file before you create the campaign. See Preview.

Variables

The agent’s script and greeting use placeholders such as {{customer_name}}. A placeholder can also have a fallback, as in {{customer_name|there}}. A key uses lowercase letters, digits and _, up to 64 characters. For each recipient and each agent variable, 60db picks the value like this:
  1. The CSV column that the variable is mapped to, if the column has a value for this row. Without a mapping, the column with the same key is used.
  2. Otherwise, the text in variable_defaults for that variable.
  3. Otherwise, the variable is not set. The call then uses the fallback written in the placeholder, if there is one.
Use variable_mapping when the variable and the column have different names. The value in the mapping is a column key, that is, the lowercase form of the header. The mapped column must exist in the CSV.
With this mapping, the agent’s customer_name comes from the name column. The agent’s plan comes from the default standard for every row, because the CSV has no plan column.

Preview

Preview checks the file without storing anything. It shows:
  • how many rows can be called, and how many cannot, with the reason for each
  • how many rows are duplicates, and how many are on the do-not-call list
  • for each agent variable, the CSV column that fills it by default and how many rows have a value
Send the agent’s agent_id with the preview to get the variable check. See Preview campaign recipients.

Start now or later

Set start when you create the campaign:
  • "now" starts the campaign on the next scheduler tick. It becomes running.
  • An ISO 8601 time with an offset or Z, in the future, such as 2026-12-01T09:00:00+05:30, makes the campaign scheduled. It starts at that instant.
A time without an offset is refused. This stops a server’s local time zone from being used by mistake.

Time zone and calling windows

The campaign timezone is an IANA name, such as Asia/Kolkata. It sets the calling windows and nothing else. start is always an exact instant. A calling window is a day list and a time range in that time zone. The default is every day, from 09:00 to 20:00. You can set up to 20 windows. Days use ISO numbers: 1 is Monday and 7 is Sunday. A window cannot cross midnight. Its end can be 24:00.
Nothing dials outside a window. A retry that is due outside a window waits for the next window to open.

Retries

Each finished call sets the recipient’s result:
  • Answered. The call connected. The recipient is completed. The failure count goes back to zero.
  • No answer. The carrier reported busy, no answer, a timeout or a decline, or the call ended without connecting. The recipient is retried, or is no_answer when no attempts are left.
  • Failed. Any other result that did not connect. The recipient is retried, or is failed when no attempts are left.
A dial that could not start does not use an attempt. This happens when the workspace is at its call limit, or when a short service problem stops the dial. The recipient is tried again soon. max_consecutive_failures counts calls in a row that did not connect. An answered call resets the count. When the count reaches the limit, the campaign pauses with the reason consecutive_failures. Resuming the campaign resets the count.

Concurrency

Concurrency is the number of calls a campaign runs at the same time. The campaign also has to fit the workspace call limit. The limit that applies is the lower of the two. The campaign response shows effective_concurrency (the number that applies), and workspace_concurrency (the workspace limit, or null for no limit). A new call starts when a call in the campaign ends.

Do-not-call

The do-not-call list belongs to the workspace. It is shared by all campaigns. A number on the list is:
  • skipped when you upload the file, with the reason dnc
  • skipped again when its call comes up, if you added it after the upload
Adding a number does not end a call that is already running. Manage the list with the API: List, Add and Remove.

Statuses and pause reasons

Campaign status draft is a valid filter value, but creating a campaign never returns it. Pause reasons Recipient status

Controls

  • Pause stops new calls. Live calls finish. Pausing works even when the plan is not active.
  • Resume starts a paused campaign again. It needs an active plan. It resets the failure count.
  • Cancel stops the campaign for good. Recipients still waiting become cancelled. Live calls finish.
A campaign that has finished cannot be resumed.

Live progress

The campaign page in the dashboard shows the counts and the recipient table for the campaign. Each recipient shows its number, its variables, its status, its attempts, its last outcome and its next attempt. The same data is available through the API:
  • Get campaign returns the counts and the concurrency.
  • List campaign recipients returns each recipient, with a filter by status. last_call_id links to the recipient’s last call.
  • Get campaign summary returns the number of running campaigns, waiting recipients and calls in progress for the workspace.
  • Each call a campaign places has metadata.campaign_id and metadata.recipient_id. See Get call.

Who can do what

API keys need the agents scope.

Example: create a campaign with the API

This example uses jq to build the JSON body from a file. Replace the placeholder ids.
Use the same Idempotency-Key when you retry step 2. The retry returns the first campaign and does not create a second one. See Create campaign.