Campaigns
Overview
Section titled “Overview”Campaigns allow you to send bulk WhatsApp messages to multiple contacts using approved templates. The API handles rate limiting and delivery tracking automatically.
List Campaigns
Section titled “List Campaigns”Retrieve all campaigns.
GET /api/campaignsQuery Parameters
Section titled “Query Parameters”| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Page size, 1–100. Default 50. |
status | string | Filter by status |
whatsapp_account | string | Filter by WhatsApp account name |
search | string | Case-insensitive match on the campaign name |
from / to | string | YYYY-MM-DD range filter on created_at (to is inclusive of the whole day) |
Ordered by created_at DESC.
Response
Section titled “Response”{ "status": "success", "data": { "campaigns": [ { "id": "uuid", "name": "Holiday Promotion", "whatsapp_account": "Main Business", "template_id": "uuid", "template_name": "holiday_offer", "status": "completed", "total_recipients": 1000, "sent_count": 1000, "delivered_count": 950, "read_count": 500, "failed_count": 50, "scheduled_at": "2024-01-01T10:00:00Z", "started_at": "2024-01-01T10:00:05Z", "completed_at": "2024-01-01T10:30:00Z", "created_by_name": "Jane Admin", "updated_by_name": "Jane Admin", "created_at": "2024-01-01T09:00:00Z", "updated_at": "2024-01-01T10:30:00Z" } ], "total": 25, "page": 1, "limit": 50 }}Get Campaign
Section titled “Get Campaign”Retrieve a single campaign with detailed progress.
GET /api/campaigns/{id}Response
Section titled “Response”{ "status": "success", "data": { "id": "uuid", "name": "Holiday Promotion", "template_id": "uuid", "template_name": "holiday_offer", "whatsapp_account": "Main Business", "status": "processing", "total_recipients": 1000, "sent_count": 450, "delivered_count": 400, "read_count": 100, "failed_count": 10, "scheduled_at": null, "started_at": "2024-01-01T10:00:05Z", "created_at": "2024-01-01T09:00:00Z", "updated_at": "2024-01-01T10:05:00Z" }}Create Campaign
Section titled “Create Campaign”Create a new campaign. Per-recipient template values are supplied when you import recipients, not
on the campaign itself — there is no variable_mapping field.
POST /api/campaignsRequest Body
Section titled “Request Body”{ "name": "New Year Sale", "whatsapp_account": "Main Business", "template_id": "uuid", "header_media_id": "", "scheduled_at": "2024-01-01T00:00:00Z"}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name |
whatsapp_account | string | Yes | Name of the sending WhatsApp account |
template_id | uuid | Yes | Template to send |
header_media_id | string | No | Meta media ID for a media-header template — upload it first with POST /api/campaigns/{id}/media |
scheduled_at | string | No | ISO-8601 time to start the campaign |
Response
Section titled “Response”{ "status": "success", "data": { "id": "uuid", "name": "New Year Sale", "status": "draft", "created_at": "2024-01-01T00:00:00Z" }}Update Campaign
Section titled “Update Campaign”Update a draft campaign.
PUT /api/campaigns/{id}Delete Campaign
Section titled “Delete Campaign”Delete a campaign.
DELETE /api/campaigns/{id}Import Recipients
Section titled “Import Recipients”Import recipients from a CSV or JSON file.
POST /api/campaigns/{id}/recipients/importRequest Body (JSON)
Section titled “Request Body (JSON)”{ "recipients": [ { "phone_number": "+1234567890", "recipient_name": "John Doe", "template_params": { "customer_name": "John", "coupon": "SAVE20" }, "header_params": { "season": "Summer" } }, { "phone_number": "+0987654321", "recipient_name": "Jane Smith", "template_params": { "customer_name": "Jane", "coupon": "SAVE15" }, "header_params": { "season": "Winter" } } ]}header_params is only needed for templates with a TEXT header variable
(Meta allows at most one). It's kept separate from template_params so a
positional header {{1}} doesn't collide with body {{1}}. Omit the field
entirely for templates without a header variable.
Response
Section titled “Response”{ "status": "success", "data": { "message": "Recipients added successfully", "added_count": 2, "total_recipients": 1002 }}added_count is the number of recipients in this request; total_recipients is the campaign's new
total.
Get Recipients
Section titled “Get Recipients”Get all recipients of a campaign with their per-recipient delivery status. This endpoint returns the full recipient list for the campaign — it is not paginated.
GET /api/campaigns/{id}/recipientsResponse
Section titled “Response”The recipients array holds every recipient; total is the count.
{ "status": "success", "data": { "recipients": [ { "id": "uuid", "campaign_id": "uuid", "phone_number": "1234567890", "recipient_name": "John Doe", "status": "delivered", "template_params": { "customer_name": "John", "coupon": "SAVE20" }, "header_params": { "season": "Summer" }, "whatsapp_message_id": "wamid.xxx", "error_message": "", "sent_at": "2024-01-01T10:00:10Z", "delivered_at": "2024-01-01T10:00:15Z", "read_at": "2024-01-01T10:05:00Z" } ], "total": 1000 }}| Field | Type | Description |
|---|---|---|
phone_number | string | Recipient phone number |
recipient_name | string | Recipient display name |
status | string | pending, sent, delivered, read, or failed |
template_params | object | Body parameter values used for this recipient |
header_params | object | TEXT-header parameter values (if any) |
whatsapp_message_id | string | Meta message ID once sent |
error_message | string | Failure reason when status is failed |
sent_at / delivered_at / read_at | string | Delivery timestamps (null until reached) |
Delete Recipient
Section titled “Delete Recipient”Remove a single recipient from a campaign. Only allowed while the campaign is in
draft status.
DELETE /api/campaigns/{id}/recipients/{recipientId}Response
Section titled “Response”{ "status": "success", "data": { "message": "Recipient deleted successfully" }}Upload Campaign Media
Section titled “Upload Campaign Media”Upload the media asset for a campaign whose template has a media header (image,
video, or document). Allowed only for draft campaigns whose template has a
non-TEXT header. The file is uploaded to WhatsApp and stored locally for preview.
POST /api/campaigns/{id}/mediaSend the request as multipart/form-data with a file field (max 16 MB).
curl -X POST "http://your-server:8080/api/campaigns/{id}/media" \ -H "X-API-Key: whm_your_api_key" \ -F "file=@banner.jpg"Response
Section titled “Response”{ "status": "success", "data": { "media_id": "meta-media-id", "filename": "banner.jpg", "mime_type": "image/jpeg", "local_path": "campaigns/uuid.jpg", "message": "Media uploaded successfully" }}Get Campaign Media
Section titled “Get Campaign Media”Serve the previously uploaded campaign media file (used for previews). Returns the raw media bytes, not a JSON envelope.
GET /api/campaigns/{id}/mediaCampaign Actions
Section titled “Campaign Actions”Start Campaign
Section titled “Start Campaign”Begin sending messages.
POST /api/campaigns/{id}/startPause Campaign
Section titled “Pause Campaign”Pause a running campaign.
POST /api/campaigns/{id}/pauseCancel Campaign
Section titled “Cancel Campaign”Cancel a campaign (cannot be resumed).
POST /api/campaigns/{id}/cancelRetry Failed
Section titled “Retry Failed”Re-queue every recipient whose delivery failed. Allowed only on completed,
paused, or failed campaigns. Failed recipients are reset to pending, the
campaign moves back to processing, and the messages are re-enqueued.
POST /api/campaigns/{id}/retry-failedResponse
Section titled “Response”{ "status": "success", "data": { "message": "Retrying failed messages", "retry_count": 12, "status": "processing" }}Get Progress
Section titled “Get Progress”Fetch live progress for a campaign. This returns the same payload as Get Campaign (status plus sent/delivered/read/failed counts) and is convenient for polling while a campaign is sending.
GET /api/campaigns/{id}/progressCampaign Status
Section titled “Campaign Status”| Status | Description |
|---|---|
draft | Campaign created, not yet started |
scheduled | Campaign scheduled for future sending |
queued | Recipients have been pushed onto the Redis job queue |
processing | Workers are actively sending messages |
paused | Campaign is paused |
completed | All messages have been processed |
cancelled | Campaign was cancelled |
failed | The campaign could not be processed |
Throughput
Section titled “Throughput”Sends are dispatched through a Redis Streams job queue and consumed by worker processes. Throughput
is governed by how many workers you run (-workers=N on server or worker), not by a built-in
per-second throttle — Whatomate does not shape traffic to your Meta messaging tier. If you
exceed your tier, Meta rejects the sends and the affected recipients are marked failed; use
Retry Failed once your limits allow.