Set Up a Progressive Dialer Campaign
Create a progressive dialer campaign with the SautiKit API, join agents by extension, and put every answered call through to a free agent.
Create a progressive dialer campaign with the SautiKit API, join agents by extension, and put every answered call through to a free agent.
A progressive dialer calls one contact for each agent who is free, and puts the person who answers straight through to that agent. No agent sits through ringing, voicemail or a busy tone, and no caller who answers is left waiting for an agent, because a call is only placed when someone is free to take it.
Use progressive dialing for collections, sales follow-ups, renewals and appointment confirmations: any list where a person should speak to each contact who picks up. If your team is large and your list answers rarely, predictive dialing keeps agents busier by dialing ahead.
This guide covers the order of the calls. Every field, error and response is in the API reference.
You can also set up the same campaign in SautiDesk without writing code: pick Progressive in the campaign setup and assign a queue or people.
dialer.write and dialer.read. Joining an extension that belongs to a person also needs dialer.supervise. Create a key.402 plan.required.Create a dialer campaign with mode set to progressive. You do not need a callback_url: answered calls go to an agent, not to your server. Turn on answering-machine detection so that voicemail is never put through to an agent.
const BASE = "https://api.sautikit.com";
const headers = {
Authorization: `Bearer ${process.env.SAUTIKIT_API_KEY}`,
"Content-Type": "application/json",
};
const campaign = await fetch(`${BASE}/v1/dialer/campaigns`, {
method: "POST",
headers,
body: JSON.stringify({
name: "November renewals",
mode: "progressive",
caller_ids: ["+254709000001", "+254709000002"],
budget_minor: 1000000,
hours: {
timezone: "Africa/Nairobi",
windows: [{ days: [1, 2, 3, 4, 5], start_minute: 540, end_minute: 1020 }],
},
retry: { max_attempts: 3, backoff_minutes: [60, 240, 1440], retry_on: ["no_answer", "busy"] },
amd: { mode: "detect_and_act", on_machine: "hangup", max_analysis_seconds: 4 },
}),
}).then((r) => r.json());
console.log(campaign.id, campaign.mode, campaign.status); // progressive draftWith more than one caller ID, each call goes out from the number that has been answered most often lately. Money fields are in minor units, so 1000000 is KES 10,000.
Add contacts as JSON or CSV. Put the agent's context in fields, such as the customer's name and what they owe, and keep your own id in external_ref so you can match the results later.
curl -s -X POST "https://api.sautikit.com/v1/dialer/campaigns/$ID/contacts" \
-H "Authorization: Bearer $SAUTIKIT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: november-renewals-batch-1" \
-d '{
"contacts": [
{ "phone": "+254700000002", "external_ref": "crm-1042", "fields": { "name": "Amina", "plan": "Gold" } },
{ "phone": "+254700000003", "external_ref": "crm-1043", "fields": { "name": "Joseph", "plan": "Silver" } }
]
}'Numbers on your do-not-call list are never dialled.
Each agent takes calls through a session on their extension. Join the campaign with the extension, then mark the session ready. A session starts paused, so nothing is dialled for an agent until they are ready.
const session = await fetch(`${BASE}/v1/dialer/campaigns/${campaign.id}/sessions`, {
method: "POST",
headers,
body: JSON.stringify({ extension_id: "2001" }),
}).then((r) => r.json());
await fetch(`${BASE}/v1/dialer/campaigns/${campaign.id}/sessions/${session.id}/ready`, {
method: "POST",
headers,
});
// Keep the session alive while the agent's softphone is open.
setInterval(() => {
fetch(`${BASE}/v1/dialer/campaigns/${campaign.id}/sessions/${session.id}/heartbeat`, {
method: "POST",
headers,
});
}, 30_000);Send a heartbeat every 30 seconds. A ready session that has not been seen for 90 seconds gets no new calls, and after 5 minutes it leaves the campaign on its own, so a closed laptop never gets a customer put through to it. To take a break, pause the session. During a call the pause takes effect when the call ends.
Get the estimate, then start the campaign. Starting spends money. You can pause at any time, and calls already in progress finish normally.
curl -s "https://api.sautikit.com/v1/dialer/campaigns/$ID/estimate" \
-H "Authorization: Bearer $SAUTIKIT_API_KEY"
curl -s -X POST "https://api.sautikit.com/v1/dialer/campaigns/$ID/start" \
-H "Authorization: Bearer $SAUTIKIT_API_KEY"From here SautiKit dials one contact for every ready agent, inside your calling hours. When a person answers, they are connected to that agent's extension. SautiKit can start dialing for an agent who is wrapping up their last call, so the next customer is on the line when they finish.
The live board shows each agent's state (ready, reserved, talking, wrap, paused) and the calls in flight. A supervisor screen can follow the same thing as a stream from campaign events.
For your own records, subscribe a webhook to dialer.call.completed and dialer.campaign.completed. Each call event carries the campaign, contact, attempt and your external_ref. When the list is done, read the campaign report or export every attempt as CSV.
A progressive dialer is an outbound calling system that places one call for each agent who is free and connects the person who answers to that agent. Agents skip ringing, unanswered calls and voicemail, and the customer who answers is put straight through to a person.
Progressive dialing places exactly one call per free agent, so no answered caller is left waiting. Predictive dialing places a few more calls than there are free agents, because some contacts will not pick up. That keeps a large team busier, at the cost of an occasional caller waiting a moment for an agent.
No. A progressive campaign connects answered calls to an agent's extension, so it does not post to your server. You still receive every result through webhooks.
Yes. Pause the campaign and update it with "mode": "predictive". Contacts, attempts and agent sessions are kept. Your plan must include predictive dialing.
Nothing is dialled. A progressive campaign only places a call when an agent is ready to take it, so it slows down when agents are busy or on a break, and speeds up again when they come back.