Skip to main content

UC-022 — Bulk WhatsApp Template Campaign

FieldValue
IDUC-022
GoalCreate and send a bulk WhatsApp campaign with approved templates
ChannelWhatsApp
Complexity⭐⭐ Intermediate
Estimated time25 minutes
APIs involvedPOST /api/partner-gateway/v1/campaigns, PUT /campaigns/{id}, GET /campaigns/{id}/price, PUT /campaigns/{id}/confirm

Real-world scenarios​

  • ShopItalia — WhatsApp promotional notification: ShopItalia sends a "Summer sales -50%" promotion to 15,000 customers via a WhatsApp template with a "Go to shop" button and header image.
  • BeautyBox — Personalized coupons: Bulk send of personalized discount coupons with customer name and unique code, tracking opens and link clicks.
  • AssicuraSemplice — Policy expiry reminder: Automatic notification to customers with policies expiring in the next 30 days, with a button for online renewal.

WhatsApp campaign lifecycle​

The diagram illustrates the cycle from draft to configuration with Meta-approved WhatsApp template, cost estimation, confirmation and monitoring of delivery and read metrics.

Prerequisites​

  • Active API Key with campaign and WhatsApp channel permissions
  • WhatsApp template approved by Meta (see UC-013)
  • Verified and active WhatsApp Business number (see UC-025)
  • Contact list created and populated (see UC-007)

Step 1 — Create the campaign as a draft​

Create a new campaign specifying the WhatsApp channel (sendingMode) and recipients taken from contact lists (destinationType: 0).

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/campaigns \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "Saldi Estivi 2026",
"description": "Promozione saldi estivi -50% con coupon personalizzato",
"sendingMode": "WHATSAPP",
"destinationType": 0
}'

Response — Campaign created​

{
"id": 3907,
"name": "Saldi Estivi 2026",
"description": "Promozione saldi estivi -50% con coupon personalizzato",
"status": "DRAFT",
"sendingMode": "WHATSAPP",
"destinationType": 0,
"readyToSend": false,
"creationDate": "2026-04-09 08:00:00.000+0000"
}

Step 2 — Configure the template and recipient list​

Associate the WhatsApp Business number, the approved WhatsApp template and the contact list with the campaign, then mark it as ready with readyToSend: true.

curl -X PUT https://api.qlara.ai/api/partner-gateway/v1/campaigns/3907 \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"sendingMode": "WHATSAPP",
"whatsappPhoneNumberId": 5,
"whatsappTemplateId": 188,
"contactListIds": [415],
"scheduledDate": "2026-06-01 08:00:00.000+0200",
"readyToSend": true
}'

Response — Campaign configured​

{
"id": 3907,
"name": "Saldi Estivi 2026",
"status": "READY_TO_SEND",
"sendingMode": "WHATSAPP",
"whatsappPhoneNumberId": 5,
"whatsappTemplateId": 188,
"contactListIds": [415],
"scheduledDate": "2026-06-01 06:00:00.000+0000",
"readyToSend": true
}
Template variables

The campaign carries no template parameters: each variable of the approved template (for example {firstName}) is filled in for every recipient from the matching field of the contact in the list. Make sure contacts have those fields populated.

Behind the scenes — Bulk WhatsApp sending and rate limiting
  1. Template validation: The gateway verifies that the template is in APPROVED status on Meta Business. Templates in PENDING or REJECTED status block the campaign.
  2. Variable resolution: The variables defined in the template are resolved per recipient from the contact record, so the campaign request never lists them.
  3. Rate limiting: WhatsApp applies throughput limits based on the Business number tier (1K, 10K, 100K msg/day). The gateway automatically manages throttling to respect the limits.
  4. Conversation window: Sending a template opens a 24-hour conversation window. User reply messages within this window have no additional cost.
  5. Quality rating: Meta monitors the template's quality rating. High block rates can lead to template suspension. Monitor post-campaign metrics.

Step 3 — Estimate the cost and confirm​

Check the recipients and the price of the campaign.

# Get the cost estimate
curl -X GET https://api.qlara.ai/api/partner-gateway/v1/campaigns/3907/price \
-H "X-Api-Key: YOUR_API_KEY"

Response — Cost estimate​

{
"id": 3907,
"name": "Saldi Estivi 2026",
"status": "READY_TO_SEND",
"sendingMode": "WHATSAPP",
"whatsappTemplateId": 188,
"contactListIds": [415],
"totalPrice": 105000000000,
"walletKind": "EURO",
"numOfDistinctContact": 15000,
"readyToSend": true
}
# Confirm and schedule the campaign (202 Accepted, no body)
curl -X PUT https://api.qlara.ai/api/partner-gateway/v1/campaigns/3907/confirm \
-H "X-Api-Key: YOUR_API_KEY"

Expected result​

StepActionResult
1POST /campaignsCampaign created with status DRAFT
2PUT /campaigns/{id}Status READY_TO_SEND with number, template and list
3GET /price15,000 distinct recipients (numOfDistinctContact) and totalPrice
4PUT /confirm202 Accepted: campaign confirmed, delivery scheduled

Complete end-to-end example​

# 1. Create WhatsApp campaign
CAMP_ID=$(curl -s -X POST https://api.qlara.ai/api/partner-gateway/v1/campaigns \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "Saldi Estivi 2026",
"description": "Promozione saldi con coupon personalizzato",
"sendingMode": "WHATSAPP",
"destinationType": 0
}' | jq -r '.id')

echo "Campaign ID: $CAMP_ID"

# 2. Configure number, template and list
curl -s -X PUT "https://api.qlara.ai/api/partner-gateway/v1/campaigns/${CAMP_ID}" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"sendingMode": "WHATSAPP",
"whatsappPhoneNumberId": 5,
"whatsappTemplateId": 188,
"contactListIds": [415],
"readyToSend": true
}'

# 3. Check the price
curl -s -X GET "https://api.qlara.ai/api/partner-gateway/v1/campaigns/${CAMP_ID}/price" \
-H "X-Api-Key: YOUR_API_KEY" | jq .

# 4. Confirm
curl -s -X PUT "https://api.qlara.ai/api/partner-gateway/v1/campaigns/${CAMP_ID}/confirm" \
-H "X-Api-Key: YOUR_API_KEY"

Variants​

Campaign with a personalized coupon code​

The campaign cannot pass a different value to each recipient: a unique coupon code has to come from the contact record. Save each customer's code on the contact (see UC-007), use an approved template whose text shows it through a variable, and point the campaign at that template:

curl -X PUT "https://api.qlara.ai/api/partner-gateway/v1/campaigns/${CAMP_ID}" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"sendingMode": "WHATSAPP",
"whatsappPhoneNumberId": 5,
"whatsappTemplateId": 192,
"contactListIds": [416],
"readyToSend": true
}'

Common errors​

400 Bad Request — Template not approved by Meta​

{
"status": "fail",
"data": {
"whatsappTemplateId": "Template not approved by Meta or not found for channel WHATSAPP"
}
}

Solution: Check the template status on Meta Business Manager. Only templates with APPROVED status can be used. See UC-013.

400 Bad Request — WhatsApp fields missing​

{
"status": "fail",
"data": {
"whatsappPhoneNumberId": "Required when sendingMode includes WHATSAPP"
}
}

Solution: Every sending mode that includes WhatsApp needs both whatsappPhoneNumberId and whatsappTemplateId. Set them with PUT /campaigns/{id} before confirming.

401 Unauthorized — Missing or invalid API Key​

{
"error": "Invalid API Key"
}

Solution: Verify that the X-Api-Key header is present and that the key is active in the platform dashboard.

Next steps​

References​