Skip to main content
A campaign can send each recipient one follow-up message. The wait starts when WhatsApp reports the first message as delivered or read, and the follow-up comes from the number that sent the first message. A recipient who replies or opts out never gets it.
Follow-ups are a beta. When the beta is offered to your team, a team owner or admin selects Join on the Receipt-timed campaign follow-ups beta row in the campaign builder’s message step, reviews the terms and selects Accept and join. Until your team has joined and the beta is available to it, requests that set a follow-up, or launch or copy a campaign that has one, answer 403 feature_unavailable. Removing a follow-up from a draft always works.

How the timing works

  • Delivery starts the wait. The follow-up is due its delay after WhatsApp first reports the first message as delivered.
  • A read takes precedence. If WhatsApp reports the first message as read before the follow-up starts sending, the wait restarts from that first read. Later reads do not move it again.
  • No receipt, no follow-up. A follow-up never sends on a timer alone. Recipients who turned off read receipts report deliveries only, so their wait starts from delivery.
  • Expiry never sends. The expiry counts from when the first message was sent. A follow-up that is not sent by then is marked expired and never sent.
The campaign’s send window also applies: a follow-up that falls due outside the window waits for the next opening, as long as it has not expired.

What cancels a follow-up

  • The recipient replies to the number that sent the first message.
  • The phone number is added to your opt-out list, whether by a STOP keyword, the API, an import or the console. A later START does not restore a cancelled follow-up.
  • You stop the campaign.
  • The sending number changes: it is renamed, connected again as a new connection, or switches sending type. A follow-up is only ever sent from the original number and connection.
  • Your team leaves the beta, or the beta is turned off.
Pausing a campaign holds follow-ups. Their waits keep counting, so a follow-up whose expiry passes while the campaign is paused expires without sending. While the sending number is offline or disabled, the follow-up waits until it returns or the follow-up expires. A follow-up that has started sending is never recalled or sent twice. If its result is unknown, for example after a connection drop, Polymorfa reconciles it from the original send and reports outcome_unknown until it can prove the outcome.

Requirements

  • The campaign sends one first message: a single composed message or a template. A campaign with a sequence of composed messages cannot launch with a follow-up.
  • The follow-up is either text (1 to 16,384 characters, with the same {{variable}} placeholders as the campaign) or a message template (templateId). Follow-up text cannot contain tracked links ({{link:key}}).
  • On a Cloud API number, the follow-up follows the same 24-hour window rule as any composed message: outside it, a text follow-up fails. Use an approved template to reach recipients outside that window.
  • The follow-up fills its variables the same way as the first message, including the campaign’s variable mapping. A recipient without a value for a variable that has no inline fallback does not get the follow-up; it ends as failed with reason missing_variable. The console accepts only variables that the first message or its mapping already uses.
  • You can add, change or remove the follow-up only while the campaign is an unlaunched draft. Launch freezes it.
  • A/B tests and weighted variations work with follow-ups: each recipient’s own first message starts their wait.
Waiting, receipts and cancellations are free. Each follow-up that is sent is a campaign message, with the same funding, plan and safety checks as the first message.

Add a follow-up

Use the console

In the campaign builder’s message step, turn on Send one follow-up, write the message or choose a message template, and set how long to wait and when to stop waiting. The review step shows the follow-up before you launch.

Use the API

Send followUp when you create or update a draft:
To send a message template instead, use "message": { "type": "template", "templateId": "<template UUID>" }. Send "followUp": null to remove the follow-up. On the Platform API, send the same field to POST /platform/campaigns or PATCH /platform/campaigns/{campaignId}. A follow-up the API refuses answers 400 invalid_parameter with param: "followUp". Launching a campaign that combines a follow-up with a message sequence answers 409 state_conflict.

Read follow-up results

Follow-up results are counted apart from the first message. The first-message counts and webhooks keep their meaning.

Campaign analytics

GET /messaging/projects/{projectSlug}/campaigns/{id}/analytics and GET /platform/campaigns/{campaignId}/analytics return a followUps object: All counts are zero for a campaign without a follow-up.

Recipients

Each recipient from GET /messaging/projects/{projectSlug}/campaigns/{id}/recipients or GET /platform/campaigns/{campaignId}/recipients has a followUp object, or null when no follow-up was created for that recipient. It includes status, anchorKind (delivered or read), firstDeliveredAt, firstReadAt, dueAt, expiresAt, sentAt, deliveredAt, readAt, repliedAt, reason and commandId. Times are Unix milliseconds. status is one of waiting_receipt, scheduled, sending, sent, cancelled, expired, failed or outcome_unknown. reason explains a cancellation, expiry, failure or wait, for example reply, opt_out, wait_expired, campaign_stop, sender_changed, feature_withdrawn, send_window, sender_unavailable or missing_variable. The recipient CSV export adds the columns followUpStatus, followUpAnchor, followUpDueAt, followUpExpiresAt, followUpSentAt, followUpReadAt, followUpRepliedAt, followUpReason and followUpCommandId.

Campaign history

GET /platform/campaigns/{campaignId}/events records each follow-up state change as a followup.<status> event, such as followup.scheduled or followup.cancelled, with the recipient, the sending number and the reason. It never contains message text or phone numbers. The same state changes appear in the Console’s Logs as campaign.followup.<status> rows. Follow-ups do not add webhook events.

Leaving the beta

Leaving the beta, or the beta being turned off, cancels follow-ups that have not started sending. Sends that already started finish and are never sent again. Joining again later does not restore cancelled follow-ups. Results stay readable, and you can still remove the follow-up from a draft.