Contacts & follow-ups

Updated July 2026

Every campaign comes down to two things: who you reach, and how persistently you reach them. This page shows you how to prepare a clean contact file, how Qalyb checks it before anything goes out, and how to keep nudging people who don't answer or reply.

WhatsApp campaigns are coming soon:
The WhatsApp channel is pending Meta app review, so WhatsApp campaigns are not yet available in the dashboard — voice and email campaigns are. The WhatsApp parts of this page describe how it will work once it launches.
Before you start, make sure you have:
Your audience in a spreadsheet you can save as a CSV file
A campaign underway — if you haven't opened the wizard yet, start with Create a campaign
For WhatsApp follow-ups: an approved template in WhatsApp Business Manager for every message you plan to send
Plans & roles:
outbound campaigns are included on the Pro, Ultra, and Enterprise plans. Admins and members can create and run campaigns; only admins can delete them.

Build your contact file

Contacts come in through the Recipients step of the campaign wizard as a CSV upload. The column Qalyb needs depends on the channel:

ChannelRequired columnWhat else is used
Voice Callphone_numbername (optional); any extra column becomes per-contact data
WhatsAppphone_numbername (optional); columns mapped to template variables
Emailemailname (optional); columns referenced as {{column}} in the subject and body

Not sure where to start? The Template button in the Recipients step downloads a starter CSV with the right header row for your channel. A voice or WhatsApp file looks like this:

contacts.csv · text
name,phone_number,booking_date,city
Amal Al-Saud,+966512345678,2026-07-02,Riyadh
Khalid Mansour,0501234567,2026-07-03,Jeddah
Noura Tariq,+971501234567,2026-07-04,Dubai

For an email campaign, swap the phone column for an email column:

contacts-email.csv · text
name,email,order_id
Amal Al-Saud,amal@example.com,ORD-4821
Khalid Mansour,khalid@example.com,ORD-4822

Any column beyond name and the destination becomes data attached to that contact. The agent can use it during the conversation, and messages can include it — so booking_date or order_id flow straight from your spreadsheet into what each person hears or reads.

What the preview checks

As soon as you drop in a CSV, the right-hand pane parses every row and tags it with a status. This is your chance to catch a bad export before any calls or messages go out.

app.qalyb.ai/campaigns/new
Screenshot: Recipients step of the campaign wizard with a CSV uploaded and a right-hand preview pane showing parsed contacts with valid, invalid, and duplicate badges
The Recipients step previews every parsed row with a live validation status before you can launch.
StatusWhat it means
ValidThe destination parsed cleanly and will be queued.
AssumedA local number was converted using the Default Country — for example 0512345678 became +966512345678. Worth a glance to confirm the country is right.
DuplicateSame destination as an earlier row. The first occurrence is kept and the rest are silently dropped.
InvalidThe phone number could not be converted to the international E.164 format, or the email address failed validation. These block the launch.

Phone numbers are checked against the Default Country you selected. GCC countries are listed first in the picker, so a Saudi local number like 05xxxxxxx resolves to +966xxxxxxx automatically. Email addresses are validated by format.

Invalid contacts block the launch:
the Launch Campaign button is disabled while any row is invalid. Fix or remove the flagged rows in your CSV and re-upload.

Required agent variables

Your agent may have required prompt variables — placeholders in its instructions with no default value. Each one needs a matching CSV column, or the launch fails. The required and optional variables show as pills back in the Sender & Agent step, so you know which columns your file needs before you upload.

Keep trying: retries for voice campaigns

Voice campaigns reach people in real time, so persistence means redialing. In the Schedule step, turn on Retry Failed Calls and set how hard Qalyb tries:

  • Max Attempts — between 1 and 5 dials per contact.
  • Wait Between Retries — anywhere from 5 minutes to 24 hours between attempts.
  • Operating Hours — a daily call window; attempts that would fall outside it are rescheduled instead of calling at a bad hour.

On the campaign detail page, the Call Log shows every contact with its attempt count. Rows with multiple attempts expand to reveal each dial — its number, outcome, duration, and time. A failed or unanswered call on an active campaign gets a retry button so you can re-queue it yourself.

Note:
manual retry only works when the call outcome is failed or no_answer and the campaign is still active (queued or running). The Call Log refreshes itself every 5 seconds while the campaign runs.

Follow-up nudges for WhatsApp and email

Messaging campaigns don't redial — they nudge. Turn on Follow up if no reply in the Send Rules step and a cadence builder appears. Stack up to 10 follow-up steps, each with its own wait time and message, and Qalyb sends the next nudge only if the contact still hasn't responded.

app.qalyb.ai/campaigns/new
Screenshot: follow-up cadence builder in the campaign wizard Send Rules step, showing two WhatsApp follow-up steps each with a wait duration and a template name
The cadence builder lets you stack up to ten timed follow-up steps per campaign.
Turn on follow-ups

In the WhatsApp or email Send Rules step, toggle Follow up if no reply on.

Add a step

Click Add follow-up step (WhatsApp) or Add follow-up email (email).

Set the wait

Set Wait before sending as a number plus a unit — Minutes, Hours, or Days. The minimum gap is 5 minutes; the maximum per step is 30 days.

Write the message

For WhatsApp, enter the step's own Template Name, Language Code, and any variable-to-column mappings. For email, enter an optional Subject and a Body — the email is sent in the same thread as the original.

Repeat and review

Stack up to 10 steps. The final review screen summarizes the cadence as N step(s) so you can confirm before launching.

When nudges stop

Follow-ups stop automatically the moment a contact replies, opts out, bounces, or fails — this stop list is fixed and not editable per campaign. If the cadence runs out with no response, the contact is marked no response.

Every WhatsApp follow-up needs its own approved template:
WhatsApp's 24-hour messaging window means each follow-up must be a separately approved template in WhatsApp Business Manager. There is no in-product template picker yet — you type the template name by hand — so approve every template you plan to use before launching.
Email follow-up content:
email follow-ups thread under the original email. In this version they reuse the campaign's base subject and body — the per-step subject and body you enter in the builder are collected but not yet applied to each step.

Watch replies come in

Once a WhatsApp or email campaign is running, its detail page shows a Delivery Funnel and a Delivery Log instead of the voice Call Log. The funnel shows how far each message got, with a count and percentage at every stage — Sent → Delivered → Read → Replied — and chips summarize the contacts who fell out: No response, Opted out, Bounced, and Failed.

app.qalyb.ai/campaigns/cmp_abc123
Screenshot: async campaign detail page with KPI cards for Total Contacts, Sent, Delivered, and Replied above a Sent-to-Replied delivery funnel and terminal-outcome chips
WhatsApp and email campaigns show a Sent → Delivered → Read → Replied funnel instead of a call log.

Each recipient in the Delivery Log carries one of these statuses. They only ever move forward — a status never downgrades, and the final states don't change:

StatusMeaning
queuedWaiting in the send queue.
sentHanded off for delivery.
deliveredConfirmed delivered to the device.
readOpened by the recipient (WhatsApp read receipt).
repliedFinal. The contact answered — handed off to the agent conversation.
no_responseFinal. The cadence finished with no reply.
opted_outFinal. The contact asked to stop.
bouncedFinal. The email bounced.
failedFinal. The send failed.

A reply is the goal: it cancels any pending follow-ups and hands the conversation to your agent. For email, a replied row shows a View conversation link that jumps straight to the inbox so you can read the thread. The Delivery Log also shows how many follow-ups were sent per recipient and the last send time.

Adding contacts after launch

You can add more contacts to an already-running campaign — but only for voice campaigns today, and only through the API (see below). For WhatsApp and email, build a new campaign with the additional audience.

Stopping a campaign

Need to pull the plug? The campaign detail header has a Cancel Campaign action while a campaign is queued or running. Cancelling sets every queued and in-flight recipient to cancelled, clears all pending follow-ups, and drains the queues so nothing else goes out.

Note:
there is no pause and resume — only Cancel. A cancelled campaign can't be restarted, so if you only need a temporary hold, schedule the campaign for a later start time instead.

For developers

Append recipients to a voice campaign with POST /campaigns/:id/contacts. For WhatsApp and email campaigns it returns Adding contacts to non-voice campaigns is not yet supported:

curl · bash
curl -X POST https://api.qalyb.ai/campaigns/cmp_abc123/contacts \
  -H "Authorization: Bearer sk-live-..." \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "phoneNumber": "+966512345678", "name": "Amal Al-Saud", "data": { "booking_date": "2026-07-02" } }
    ]
  }'

Re-queue a single failed or no-answer call on an active campaign — the same action as the Call Log's retry button:

curl · bash
curl -X POST https://api.qalyb.ai/campaigns/cmp_abc123/calls/call_789/retry \
  -H "Authorization: Bearer sk-live-..."

On create, POST /campaigns rejects lists containing invalid rows and returns them as invalidContacts; a contact missing a required agent variable fails with Contacts are missing required agent variables.

Was this guide helpful?