Outbound campaigns

A campaign points an agent at a list of contacts and calls them, tracking each one.

Contacts

Upload a CSV or paste a list when you create the campaign. To add contacts to an existing campaign, sync them from a CSV or from a URL your own system serves; the URL source is only available on that sync, not at creation. All of these go through the same reader.

The phone column is found for you: by its header in English or Turkish, or - when the file has no header - by which column actually contains phone numbers. The response tells you which column it used, so a file read from the wrong one is distinguishable from a file that could not be read at all. Semicolon-separated exports work, which is what Excel writes in every locale that uses a comma for decimals.

Numbers are converted to international (E.164) form on the way in, so a list pasted from a spreadsheet works as-is and the same person cannot enter one campaign twice under two spellings. Rows that hold no usable number are counted and reported rather than dropped in silence, which is usually how you find out a column was shifted.

A number written in national form (0532 123 45 67) has no country in it, so one is assumed: the country of the campaign's own caller ID. That is a fact about the campaign rather than a setting anyone has to remember, and it is per campaign, which a single account-wide default could never be. The receipt below reports which region was assumed, how many rows needed it, and a few of them as written-and-dialed pairs, so the assumption can be checked against real values instead of trusted.

This is the one import mistake that does not look like a mistake. A national number completed against the wrong country becomes a perfectly valid number somewhere else: it is not rejected, it is counted as added, and it dials a stranger. If country_code_added is non-zero, read assumed_region and the samples before you start the campaign.

Every other column becomes a variable on that contact and travels with their call, so a prompt that says {'{{name}}'} greets the person being called and can reference their order without a separate lookup.

What the import tells you

Reading a list returns a receipt, on both the create call and the contacts sync. An outbound launch cannot be taken back, so what the file became is worth reading before it dials rather than after.

addedNew contacts on the campaign.
skippedAlready on this campaign before the import.
duplicatesThe same number more than once inside the file.
rejectedRows holding no usable phone number.
phone_columnThe column the numbers were read from.
on_do_not_callOf what was added, how many are suppressed and so will never be dialed.
assumed_regionThe country national-format numbers were completed against. Empty when every row carried its own country code.
country_code_addedHow many rows needed that assumption.
assumed_samplesA few of those rows as written-and-dialed pairs, to check the assumption against.

added is normally the number worth checking against the row count you expected. When it comes up short, skipped, duplicates and rejected say which of the three reasons it was. When it comes out right, country_code_added is the one still worth a look - those rows were added, and they may not be the numbers you meant.

Progress

A campaign reports its own tallies, so you can draw progress without fetching its contacts: total, pending, dialing, answered, voicemail, no_answer, failed, suppressed, and dialed for everything handed to the carrier including calls still in flight.

Measure against dialable, which is total minus suppressed, not against total. Suppressed numbers are on the do-not-call list and will never be dialed, so a campaign measured against total stops short of finished for good.

Editing, duplicating and exporting

A campaign can be renamed at any point. Its schedule and its calling hours can only be changed before it starts: moving the start time of one already dialing would say nothing about the calls it has already placed, and moving one that has finished would misstate its history, so both are refused rather than quietly ignored.

Duplicating copies the setup and the contact list into a fresh draft, and dials nothing. Outcomes are not copied, so it is the way to run the same list again or to reuse a configuration against a new one.

Exporting downloads the contacts as CSV with what came of each: phone, outcome, dialed_at, error and session_uuid. The session uuid is what joins a result back to the conversation that produced it.

Starting

Start a campaign immediately, or create it with a scheduled_at start time and it starts itself shortly after that moment. A start time that is absent or already in the past leaves the campaign a draft, to be started by hand.

scheduled_at must carry its own UTC offset or time zone (2026-10-01T09:00:00+03:00 or 2026-10-01T06:00:00Z). The campaign's timezone setting does not apply to it: that setting is for the calling window only.

A scheduled campaign has not started, so stop does not apply to it and is refused with 409 campaign_not_running. To cancel the schedule, update the campaign with scheduled_at set to null (unschedule in the SDKs); it returns to a draft and dials nothing until started.

Caller ID

A campaign dials from a number your organization has connected. Any other number is refused: presenting a caller ID you do not hold is what gets a line blocked by a carrier, and it is not something a platform should let you do by accident.

Calling hours

A campaign can be limited to a window of hours in a time zone you choose, set as a start and an end time; sending only one of the two is refused. A window whose end is earlier than its start crosses midnight (22:00 to 06:00). Outside the window the campaign's status is waiting, and it resumes by itself when the window opens, rather than working through the night because the list happened to be long. The window is checked before each dial, so a call already connected when it closes finishes normally.

The window belongs to the campaign, not to each number. Deriving hours from a number's country reads plausible but is wrong often enough to be worse than useless: a mobile number keeps its prefix wherever its owner lives.

Stopping and resuming

Starting dials the contacts that have not been called yet. Stop applies to a campaign that is running or waiting, and takes effect at the next contact: calls already connected finish normally, and undialed contacts stay ready, so starting again resumes rather than calling everyone a second time.

A campaign moves to a resting status on its own, and status_detail says why:

StatusWhy
completedEvery contact reached a final outcome.
haltedToo many consecutive dial failures, which usually means a carrier or number problem rather than a bad list.
out_of_creditThe balance fell below what a call needs, before or during the run. Top up and start it again.
failedIt could not dial at all: the caller ID is no longer connected to your organization, or its carrier account is not configured.

The full set of statuses is draft, scheduled, running, waiting, stopped, completed, halted, out_of_credit and failed.

Outcomes

Every contact ends in one of:

  • Answered - the call reached the agent and a conversation happened. It links to a normal session with the full transcript and cost, and the recording when recording is on for the agent.
  • Voicemail - the carrier's answering-machine detection found a recording. This needs voicemail detection enabled on the agent and a carrier that offers it; a SIP Trunk (direct) number has no answering-machine detection, so its calls never end in this outcome.
  • No answer - the number was dialed but no call ever connected.
  • Failed - the carrier refused the number. Its own reason is shown.
  • Do not call - the number is on your suppression list, so it was never dialed.

Busy is not reported separately from no answer. Telling them apart needs per-carrier status callbacks that are not collected, and reporting a distinction that was never observed would be worse than reporting neither.

Do not call

Contacts are checked against your do-not-call list before they are dialed, in a batch each time the campaign begins or picks up again, not one by one at the moment of dialing. A number added to the list while a campaign is running can therefore still be called by that campaign. If a number must not be called, stop the campaign, add the number, then start it again. Suppressed contacts are marked as such rather than as failures, so they neither look like a problem nor count toward the failure limit that halts a campaign.

How much of the list a campaign honours

Someone who refused marketing has not refused a call about their own order, so blocking every call would mean deciding something they never said. Two settings decide, and they compose.

The first belongs to the entry: a request an agent recorded on a call applies to every call, while an entry you add or import applies to marketing only. The second belongs to the campaign:

  • Respect the whole list - the default. Nobody on it is called.
  • Transactional calls - orders, appointments, deliveries. Reaches people whose entry is marketing-only.
  • Ignore my own entries - skips what you added or imported. Requests people made on a call still apply.

Choosing anything other than the default is recorded in the audit log against whoever created the campaign. Before creating it, the suppression preview reports how many of a list each option would reach, including how many of those people asked on a call not to be contacted. Send the campaign's from_number with the preview so national-format numbers are read against the same country the campaign will use; without it they are read against a platform default, and the counts may not match what the campaign dials.

Calling those people anyway is possible: it is a separate confirmation on top of the last option, never a default, and it names the number of people it covers. It is your decision and your obligation; the platform makes sure it is a deliberate one. A single number can also simply be removed from the list.

Calls placed through the API stay strict: they cannot say what kind of call they are, so the whole list applies.

Calling a list is where regulation bites hardest: consent, calling hours, do-not-call lists and identifying yourself all vary by country. Glytos gives you the controls; the obligation is yours.