UC-030 — Complete Template Lifecycle (Test, Campaign, Analysis)
| Field | Value |
|---|---|
| ID | UC-030 |
| Goal | Manage the full lifecycle of a WhatsApp template: creation, approval, test, campaign and analysis |
| Channel | |
| Complexity | ⭐⭐⭐ Advanced |
| Estimated time | 30 minutes (excluding Meta approval times) |
| APIs involved | POST /api/partner-gateway/v1/whatsapp/templates, POST /api/message-server/whatsapp/send, POST /api/partner-gateway/v1/campaigns, PUT /api/partner-gateway/v1/campaigns/{id}/confirm, POST /api/partner-gateway/v1/exports/delivery-reports, GET /api/partner-gateway/v1/exports/{exportId} |
Real-world scenarios
- FashionOutlet — New promotion launch: The marketing team creates a WhatsApp template for the summer sales, tests it in simulation, then uses it for a campaign to 20,000 VIP customers. After the campaign concludes, they export results to calculate ROI.
- ClinicaSalute — New service template onboarding: The clinic creates a template to promote a new telemedicine service. After Meta approval, they test it on a small group, verify the visual rendering and then launch the campaign.
- BancaAdriatica — Template A/B testing: The CRM team creates two template variants for a personal loan promotion. They test both on reduced samples, compare delivery and read rates, then use the winning variant for the bulk send.
:::info Composite use case This UC combines the flows from UC-013 — WhatsApp Template Workflow, UC-006 — Bulk Campaign and UC-011 — Export Delivery Reports into a complete lifecycle. :::
Prerequisites
Before you begin, make sure you have:
- Active API Key → How to get one
- Sufficient credit → Check in the Qlara Dashboard
- WhatsApp
phoneNumberId+ contact list
:::tip Test without costs
Add "simulation": true in the request body to validate the flow without actually sending messages and without consuming credit.
:::
Lifecycle flow
The diagram illustrates the complete cycle: from template creation to campaign, through to results analysis for iteration and improvement.
Step 1 — Create the WhatsApp template
Submit the template to Meta for approval:
curl -X POST "https://lora-api.agiletelecom.com/api/partner-gateway/v1/whatsapp/templates" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "promo_estate_2026",
"language": "it",
"category": "MARKETING",
"components": [
{ "type": "HEADER", "format": "IMAGE",
"example": { "header_handle": ["https://fashionoutlet.it/media/saldi-estate-2026.jpg"] } },
{ "type": "BODY",
"text": "Ciao {{1}}! Saldi estivi FashionOutlet: fino al {{2}}% di sconto. Offerta valida fino al {{3}}!",
"example": { "body_text": [["Marco", "40", "30 giugno"]] } },
{ "type": "FOOTER", "text": "FashionOutlet - Moda per tutti" },
{ "type": "BUTTONS", "buttons": [
{ "type": "URL", "text": "Scopri le offerte", "url": "https://fashionoutlet.it/saldi?ref={{1}}", "example": ["campaign_estate_2026"] },
{ "type": "QUICK_REPLY", "text": "Non mi interessa" }
]}
]
}'
Response — Template submitted
{ "templateId": "tpl_8a9b0c1d-2e3f-4a5b-6c7d-8e9f0a1b2c3d", "name": "promo_estate_2026", "status": "PENDING", "category": "MARKETING" }
:::info Meta approval times Template approval by Meta typically takes from a few hours to 24 hours. MARKETING templates take longer than UTILITY or AUTHENTICATION ones. Configure a webhook to receive the approval or rejection notification. :::
Step 2 — Wait for approval and check the status
Periodically check the template status:
curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/whatsapp/templates/tpl_8a9b0c1d-2e3f-4a5b-6c7d-8e9f0a1b2c3d" \
-H "X-Api-Key: YOUR_API_KEY"
Response — Template approved
{ "templateId": "tpl_8a9b0c1d-2e3f-4a5b-6c7d-8e9f0a1b2c3d", "status": "APPROVED", "qualityScore": "GREEN", "approvedAt": "2026-04-09T18:30:00+02:00" }
Behind the scenes — Quality Score and limits
- Quality Score: GREEN/YELLOW/RED based on user interactions. A low score limits volume.
- Sending tier: From tier 1 (1K conversations/day) to tier 4 (unlimited), grows with quality.
- Rejection: Common reasons -- aggressive language, missing opt-out, improper placeholders. Edit and resubmit.
Step 3 — Test the template in simulation
Before the campaign, verify the template with a simulation send ("simulation": true):
curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"sender": "+393801234567",
"simulation": true,
"content": {
"templateName": "promo_estate_2026",
"language": "it",
"components": [
{ "type": "body", "parameters": [
{ "type": "text", "text": "Marco" },
{ "type": "text", "text": "40" },
{ "type": "text", "text": "30 giugno" }
]}
]
}
}'
Response — Simulation successful
{
"messageId": "e5f6a7b8-c9d0-1e2f-3a4b-5c6d7e8f9a0b",
"simulation": true,
"results": { "whatsapp": { "accepted": true, "reasons": [] } }
}
:::tip Real test send
After the simulation, send a real test to your personal number (without "simulation": true) to verify the visual rendering on the device.
:::
Step 4 — Create and launch the campaign
With the template tested, create the campaign and confirm the send:
curl -X POST "https://lora-api.agiletelecom.com/api/partner-gateway/v1/campaigns" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Saldi Estate 2026 - WhatsApp VIP",
"channel": "WHATSAPP",
"sender": "+393801234567",
"contactListId": "lst_clienti_vip_2026",
"whatsappTemplate": {
"templateName": "promo_estate_2026",
"language": "it",
"bodyParameters": ["firstName", "discountPercent", "expiryDate"]
}
}'
Response
{ "id": "cmp_2c3d4e5f-6a7b-8c9d-0e1f-2a3b4c5d6e7f", "status": "DRAFT", "totalContacts": 20150 }
Confirm the send with PUT /campaigns/{id}/confirm.
Step 5 — Monitor and export
Monitor with GET /campaigns/{id}/stats until status: "COMPLETED", then export the report with POST /exports/delivery-reports (see UC-029 for the full export flow).
{
"campaignId": "cmp_2c3d4e5f-6a7b-8c9d-0e1f-2a3b4c5d6e7f",
"status": "COMPLETED",
"stats": {
"totalMessages": 20150, "delivered": 18935, "read": 12480,
"failed": 695, "deliveryRate": 93.97, "readRate": 65.91,
"totalCost": 1612.00
}
}
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | POST /whatsapp/templates | Template submitted, status: "PENDING" |
| 2 | GET /whatsapp/templates/{id} | status: "APPROVED", qualityScore: "GREEN" |
| 3 | POST /whatsapp/send (simulation) | simulation: true, accepted: true |
| 4 | POST /campaigns + PUT /confirm | Campaign created and confirmed |
| 5 | GET /campaigns/{id}/stats + export | deliveryRate: 93.97%, downloadable CSV |
Complete end-to-end example
#!/bin/bash
API_KEY="YOUR_API_KEY"
PG="https://lora-api.agiletelecom.com/api/partner-gateway/v1"
MS="https://lora-api.agiletelecom.com/api/message-server"
# 1. Create template
TPL_ID=$(curl -s -X POST "${PG}/whatsapp/templates" -H "X-Api-Key: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"name":"promo_estate_2026","language":"it","category":"MARKETING","components":[{"type":"BODY","text":"Ciao {{1}}! Saldi: -{{2}}% fino al {{3}}!"}]}' | jq -r '.templateId')
# 2. Wait for approval
while true; do
S=$(curl -s "${PG}/whatsapp/templates/${TPL_ID}" -H "X-Api-Key: ${API_KEY}" | jq -r '.status')
[[ "$S" == "APPROVED" ]] && break; [[ "$S" == "REJECTED" ]] && exit 1; sleep 300
done
# 3. Simulation test
curl -s -X POST "${MS}/whatsapp/send" -H "Content-Type: application/json" -H "X-Api-Key: ${API_KEY}" \
-d '{"destination":"+393471234567","sender":"+393801234567","simulation":true,"content":{"templateName":"promo_estate_2026","language":"it","components":[{"type":"body","parameters":[{"type":"text","text":"Marco"},{"type":"text","text":"40"},{"type":"text","text":"30 giugno"}]}]}}' | jq .
# 4. Campaign → 5. Monitor → Export (see UC-029 for the full export flow)
CMP_ID=$(curl -s -X POST "${PG}/campaigns" -H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{"name":"Saldi Estate 2026","channel":"WHATSAPP","sender":"+393801234567","contactListId":"lst_clienti_vip_2026","whatsappTemplate":{"templateName":"promo_estate_2026","language":"it","bodyParameters":["firstName","discountPercent","expiryDate"]}}' | jq -r '.id')
curl -s -X PUT "${PG}/campaigns/${CMP_ID}/confirm" -H "X-Api-Key: ${API_KEY}" > /dev/null
Variants
A/B Testing with two templates
Create two variants (e.g., urgent tone vs friendly), wait for approval of both, then launch two campaigns on different segments of the same list. Compare deliveryRate and readRate in their respective reports.
Template with tracked opt-out button
The Quick Reply "Non mi interessa" button generates an INBOUND webhook with the button text, which you can use to update the contact's preferences (see UC-028).
Common errors
Template rejected by Meta
{ "templateId": "tpl_8a9b0c1d", "status": "REJECTED", "rejectionReason": "Template content violates WhatsApp Commerce Policy" }
Solution: Common reasons: aggressive language, unrealistic promises, missing sender identity. Edit and resubmit.
Campaign with unapproved template
{ "status": "fail", "data": { "error": "Template 'promo_estate_2026' is not in APPROVED status" } }
Solution: Only templates with status: "APPROVED" can be used in campaigns. Check the status before creating the campaign.
Next steps
- UC-013 — WhatsApp Template Workflow: Learn more about template management
- UC-006 — Bulk SMS Campaign: Details on campaign creation
- UC-011 — Export Delivery Reports: Learn more about async exports
- UC-029 — Complete Campaign Report: Detailed campaign results analysis