Docs

Campaigns

Broadcast an approved template to an audience — now, later or on a schedule — with live stats.

GET/v1/campaigns
POST/v1/campaigns
POST/v1/campaigns/estimate— Recipients, exclusions and cost
POST/v1/campaigns/{id}/launch
POST/v1/campaigns/{id}/pause
POST/v1/campaigns/{id}/resume
POST/v1/campaigns/{id}/cancel
GET/v1/campaigns/{id}/report

Create a campaign

Parameters
  • namestringrequired
    Internal name.
  • phone_number_iduuidrequired
    Sending number.
  • template_iduuidrequired
    An APPROVED template.
  • audienceobjectrequired
    lists, segments, tags, contact_ids (union) minus exclude_tags.
  • variablesobjectoptional
    Maps each template parameter to a static value or a contact field, with fallback.
  • schedule_typeenumrequired
    now · at · recurring
  • scheduled_atdatetimeoptional
    Required when schedule_type is at.
  • recurrenceobjectoptional
    e.g. { "frequency": "weekly", "by_weekday": [1], "time": "10:00" }
  • timezonestringrequired
    IANA timezone, e.g. Asia/Kolkata.
  • throttle_per_minintegeroptional
    Max messages per minute.
  • send_windowobjectoptional
    e.g. { "start": "09:00", "end": "21:00" }; sending pauses outside it.
POST /v1/campaigns
{
  "name": "Festive sale — VIPs",
  "phone_number_id": "1c2d…",
  "template_id": "3c7d…",
  "audience": { "lists": [], "segments": ["5e6f…"], "tags": ["7f…"], "contact_ids": [], "exclude_tags": ["9a…"] },
  "variables": {
    "body.1": { "source": "name", "fallback": "there" },
    "body.2": { "source": "attribute", "key": "city", "fallback": "your city" },
    "button.0": { "source": "static", "value": "FESTIVE30" }
  },
  "schedule_type": "at",
  "scheduled_at": "2026-11-14T04:30:00Z",
  "timezone": "Asia/Kolkata",
  "throttle_per_min": 2000,
  "send_window": { "start": "09:00", "end": "21:00" }
}

Variable sources: static (uses value), name, phone, or attribute (uses key). fallback is used when the contact field is empty.

Estimate before launch

POST /v1/campaigns/estimate → 200
{
  "recipients": 48210,
  "excluded": { "opted_out": 1204, "blocked": 37, "no_address": 12 },
  "estimated_cost": { "currency": "INR", "amount": 37845.5 },
  "messaging_limit": "TIER_100K"
}
Messaging limits
WhatsApp limits how many unique people a business portfolio can message in a rolling 24 hours. Campaigns larger than your limit are paced automatically across days.

Lifecycle

StatusMeaning
draftCreated, not launched; editable
scheduledWill start at scheduled_at; editable
runningSending
pausedPaused; resume to continue
completedAll recipients processed
cancelledStopped; remaining recipients skipped

Report

GET /v1/campaigns/{id}/report
{
  "stats": { "total": 48210, "queued": 0, "sent": 48210, "delivered": 46480,
             "read": 34612, "failed": 1730, "replied": 2210, "skipped": 0 },
  "errors": [
    { "code": 131049, "title": "Per-user marketing limit reached", "count": 1288 },
    { "code": 131026, "title": "Message undeliverable", "count": 442 }
  ]
}

Subscribe to campaign.progress and campaign.completed webhooks for push updates.