What you’d build yourself, and what a campaign does instead
You can dial a list with the calling API alone, and plenty of people start there. Here’s what we take over when you use a campaign:
Everything else is the same call: the same assistant, the same session record, the same four webhooks, with a
campaignId on each one.
Your first campaign
All of this is in the portal too. Over the API it’s five requests. Fill in a draft in any order and update it section by section. Each update sends the whole section. Launch rejects a draft with no assistant, or a static one with no list. It doesn’t check the goal or the window, so set both first.1
Make the contact list
Create a contact list from pasted rows, an uploaded file, or a Google Sheet. We drop bad numbers, collapse duplicates by number, and tell you how many made it. Keep the
listId.2
Create the campaign
Create a campaign with The goal picks which tool the agent uses to record the outcome. A payment reminder gets
mode: bounded, the assistant that dials, the goal, the list, a calling window, and a retry policy.A payment reminder run, one line, three attempts
record_payment_promise, an order confirmation gets record_order_confirmation. Goals & scorecards has the rest. Send all three fields of the retry policy, or none. We ignore a partial one and apply the defaults: three attempts, ten minutes and then an hour apart. They retry on no answer, busy, voicemail, silent pickups, unreachable, and failed dials. Leave lines at 1 until your account has more. Scheduling & retries covers the details.3
Add a scorecard
Optional for launch, and I recommend it. A scorecard is a set of rules that add up to 100 points, and we grade every connected call against it. The grade is the score and sentiment on the calls list. Without one we grade nothing. Today that means the results list stays empty and only
call.completed fires. Scorecards shows how to write one. The scorecard goes on config.scorecard, on create or in an update.4
Launch
Launch now, or schedule a time. Launch copies the list into the campaign, so rows added to the list afterwards never dial.
5
Watch it, then read the results
Get the campaign for
state. List its calls for one row per contact, dialed or not, with the attempts so far, the next due time, and the score once graded. Add ?include_summary=true and each row carries its call’s summary. When the list runs out the campaign completes on its own.Results has one row per call with a recorded outcome: a promise to pay, a booking, a qualified lead. Stats has the totals. Each call’s callId is a session id, so percent-encode it and read the call in full. Or don’t poll at all: the webhooks deliver each call as it lands.Where your contacts come from
Three ways in, and all of them end in alistId:
- Paste rows. Put a name and a number per line straight in the create request, like the example above.
- Upload a file. Send a CSV or an Excel
.xlsxfile, check the column mapping we detected, then create the list from theuploadId. - Link a Google Sheet. Share the link, or connect a private sheet through Google. We pull it once into a list.
Static or continuous
mode is fixed at creation. It’s the one thing a draft can’t change.
- Static,
boundedin the API, dials a list you have today and completes when the list is done. This month’s dues. Make the list, create, launch or schedule, read the results. - Continuous takes contacts for as long as it runs and ends when you close it. Every new order. Create, launch with nothing, append as events happen, close.
Continuous, driven by your system
This is the same campaign, except your system feeds it. Create it withmode: continuous and no list, then launch it. It sits in running with nothing to do until you send work. On every event on your side, append contacts:
A new order, appended the moment it's placed
- Send an
externalRef. Your order id. We tell contacts apart by it. Send the same ref while the call is still pending and nothing changes. Send it again once the contact is done and we queue a fresh call, so a reorder next week works. Without it, each request enrolls the number again. - Append up to a thousand at a time. The contacts dial right away, inside the window. We skip a bad row, and the response says which and why.
- Close it when the source dries up. Close stops new contacts, lets the queue and the retries finish, and completes. There’s no undo.
campaignId and the call id embeds the contact, so your endpoint can tie a call.completed back to the order that caused it. That’s the whole loop: order placed, append, call, result.
Tech details for techies
- One line, one call at a time. The dialer looks for work every five seconds and dials as lines free up. On one line, figure a few dozen attempts an hour. An unanswered dial frees the line in about a minute. A conversation holds it for the call plus grading. A list of three hundred is a day or more once you count retries. Phone numbers & concurrency is where more lines come from.
- Out of credits pauses the campaign.
statusMessagesays so. Top up, then resume. - A deleted assistant pauses it too.
statusMessagereadsPaused: assistant version not found, and that attempt counts. Once a campaign is scheduled or launched its assistant can’t change, so start a new campaign. - A campaign dials the assistant’s published version. Publish, and the next dial uses the new one. To hold a campaign on one version, set
config.assistantVersionto its number — see Draft and publish. - Pause stops new dials only. Calls already up finish and get graded. Retries keep their times and go out after resume.
- A campaign runs once. When it completes there’s no relaunch. Next month’s dues are a new campaign.
- Stats sample the thousand most recently touched contacts. The call counters are exact, but the contact counts (attempted, retrying, exhausted) stop there. For a bigger campaign, page through the calls list.
