Campaign API
Send an approved template with one request
Create an API campaign in the app by naming it and picking an approved template. It goes Live at once and stays Live; your systems trigger each send. The campaign page shows a cURL command with your real key and a payload sized to the template, so the first request is copy and paste.
The payload mirrors the shape most WhatsApp API providers use, so an integration written for another platform ports with little change.
Authentication
Use the workspace campaign API key, shown masked in the Developer hub with reveal, copy and regenerate. Send it either as a Bearer token in the Authorization header or as an apiKey field in the body. Regenerating the key revokes every earlier key instantly.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
| campaignName | string | Yes | The name of a Live API campaign in your workspace. Chooses the template. |
| destination | string | Yes | The recipient's phone number with country code, for example +2567XXXXXXXX. |
| userName | string | No | The recipient's name. Used when the contact is created and available to template variables. |
| templateParams | string[] | No | Positional values for the template's body variables, in order. Must match the template's variable count. |
| media | { url, filename } | No | A publicly reachable URL and filename for the template's header image, video or document. |
| tags | string[] | No | Existing tag names to apply to the contact. Unknown tags are ignored. |
| attributes | object | No | Custom attribute values keyed by attribute name, written to the contact record. |
| source | string | No | Where the lead came from, for example "Website form". Stored on the contact for segmentation. |
| apiKey | string | No | The campaign API key, if you prefer it in the body rather than the Authorization header. |
Example request
curl -X POST "https://<your-api-base>/campaign/api" \
-H "Authorization: Bearer <campaign-api-key>" \
-H "Content-Type: application/json" \
-d '{
"campaignName": "order-shipped",
"destination": "+2567XXXXXXXX",
"userName": "Amina",
"templateParams": ["Amina", "LUM-4821", "Thursday"],
"tags": ["customer", "shipped"],
"attributes": { "order_id": "LUM-4821" },
"source": "Shop checkout"
}'The base URL and your key are filled in for you on the campaign page in the app. The example above uses placeholders.
What each request does
- Resolves the contact by phone number or creates it, then applies the tags, attributes and source.
- Fills the template's body and URL-button variables from templateParams and sends the message.
- Returns the message, contact and campaign IDs so you can reconcile the send in your own system.
- Counts one message per request in the campaign's metrics, since one contact may receive many.
Requests that are refused, with a clear error
- The workspace subscription is inactive.
- The campaign name does not match a Live API campaign.
- The template is not approved by Meta.
- The contact is blocked.
- The contact has opted out of marketing and the template is a marketing template.
- The destination is a United States number and the template is a marketing template, which Meta does not allow.
Webhooks
Four events, signed and retried
Add as many endpoints as you need in the Developer hub, choose the events each one receives, and reveal or regenerate its signing secret. Every attempt is logged with the event, attempt number, response code and error, with a Retry button on failures.
Events
- message.received
- A customer sent a message to your number.
- message.status_updated
- A message you sent was delivered, read or failed.
- conversation.assigned
- A conversation was claimed, taken over or transferred to a team member.
- campaign.completed
- A broadcast campaign finished sending, including retries.
Verifying a delivery
- Each delivery carries a timestamp and an HMAC-SHA256 signature computed over the timestamp and the raw body with your endpoint's secret, the same scheme Stripe and GitHub use.
- Recompute the digest from the raw body, compare in constant time, and reject anything whose timestamp is more than 300 seconds old.
- Every event has a stable ID that stays the same across retries and across endpoints. Store it and drop duplicates.
- The exact header names and a copyable PHP verification snippet are on the docs page in the Developer hub.
Delivery rules
- Five attempts, with backoff of 10, 60, 300 and 900 seconds between them, about 21 minutes in total.
- Retried on 5xx responses, timeouts and 429. Not retried on other 4xx responses.
- After 10 consecutive failed deliveries the endpoint is switched off and the reason is recorded. Re-enable it from the Developer hub.
- Endpoints on private or internal addresses are refused, and redirects are not followed.
What the API does not cover
The campaign API is the only public API. Contacts, conversations and messages are managed in the app and reach your systems through webhooks. For reading and writing data from the AI agent, use the Google Sheets, MCP server and HTTP connector tools on the integrations page.
See integrationsPut your WhatsApp number to work, free for 7 days
Unlimited seats, contacts, messages, campaigns and forms. 2,000 AI replies a month. One plan, everything included. Start today, no card needed.

