Skip to main content

UC-024 — Templates with Tracked Links

FieldValue
IDUC-024
GoalCreate WhatsApp templates with tracked buttons to measure CTR
ChannelWhatsApp
Complexity⭐⭐⭐ Advanced
Estimated time30 minutes
APIs involvedPOST /api/message-server/whatsapp/templates, POST /api/message-server/whatsapp/send

Real-world scenarios​

  • ShopItalia — Measure CTR: Track how many users click the "Go to shop" button in the promotional template to calculate the campaign conversion rate.
  • TravelDream — Landing page tracking: Each recipient receives a unique link to the travel offer landing page, with UTM parameters for Google Analytics analysis.
  • MarketingPro — A/B testing links: Send two template variants with different links (landing A vs landing B) to determine which converts better.

The diagram shows the complete cycle: template creation with tracking, delivery to the recipient and click capture with transparent redirect to the landing page.

Prerequisites​

  • Active API Key with WhatsApp template permissions
  • Verified WhatsApp Business number (see UC-025)
  • HTTPS landing page ready for tracking
  • Familiarity with WhatsApp templates (see UC-013)

Create a WhatsApp template with trackButtonLinks: true to enable automatic click tracking. The phoneNumberId query parameter associates it with your WhatsApp Business number, and the button keeps your landing page URL, UTM parameters included:

curl -X POST "https://api.qlara.ai/api/message-server/whatsapp/templates?phoneNumberId=5" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "promo_estate_tracked_2026",
"lang": "it",
"category": "MARKETING",
"headerFormat": "IMAGE",
"headerMediaUrl": "https://cdn.shopitalia.it/promo/estate-2026-header.jpg",
"body": "Ciao {firstName}, i saldi estivi sono arrivati! Sconto del 50% su tutta la collezione fino al 30 giugno.",
"buttons": [
{
"type": "URL",
"text": "Vai allo shop",
"url": "https://shopitalia.it/promo/estate2026?utm_source=whatsapp&utm_campaign=promo_estate"
}
],
"trackButtonLinks": true
}'

Placeholders must be contact fields of your account, such as {firstName}: fixed values like the discount and the end date go straight into the text.

Response — Template submitted​

The API answers 201 Created with the template in PENDING status. Below are its main fields: in buttons the URL is now the tracking link registered with Meta, while your URL stays in originalButtonUrls.

{
"id": 187,
"phoneNumberId": 5,
"name": "promo_estate_tracked_2026",
"slug": "promo_estate_tracked_2026",
"category": "MARKETING",
"lang": "it",
"status": "PENDING",
"createdAt": "2026-04-09 10:00:00.000+0000",
"updatedAt": "2026-04-09 10:00:00.000+0000",
"headerFormat": "IMAGE",
"body": "Ciao {firstName}, i saldi estivi sono arrivati! Sconto del 50% su tutta la collezione fino al 30 giugno.",
"originalButtonUrls": [
{
"index": 0,
"url": "https://shopitalia.it/promo/estate2026?utm_source=whatsapp&utm_campaign=promo_estate"
}
],
"placeholders": ["firstName"]
}
Meta approval

The template must be approved by Meta before use. The process typically takes from a few minutes to 24 hours. Monitor the status with a GET on the template.

Behind the scenes — How link tracking works
  1. URL rewriting: When trackButtonLinks: true is active, the gateway registers the button with Meta under an intermediate tracking URL and keeps the original URL in originalButtonUrls. Each message sent then gets its own short code in that URL.
  2. Click capture: When the recipient clicks the button, the request passes through the tracking service which records: timestamp, recipient, template, campaign.
  3. Transparent redirect: After recording the click, the tracking service performs an HTTP 302 redirect to the original landing page URL.
  4. UTM parameters: UTM parameters in the original URL are preserved in the redirect, allowing attribution in Google Analytics or other analytics tools.
  5. Available metrics: Total clicks, unique clicks, CTR (clicks/delivered), average time to click, hourly click distribution.

Step 2 — Send the message with tracked template​

Once the template is approved, send the message with its id and the values of its placeholders. The tracked button needs nothing more: the header image saved with the template is used too.

curl -X POST https://api.qlara.ai/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"phoneNumberId": 5,
"messageId": "wa-msg-trk-2026-04-09-001",
"template": {
"id": 187
},
"placeholders": {
"firstName": "Marco"
},
"enableNotification": true
}'

Response — Message accepted​

{
"messageId": "wa-msg-trk-2026-04-09-001",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
}
}
}
No links in the response

The send response does not list the tracking links: each message gets its own short link to the URL of originalButtonUrls when it is sent. Use the messageId to correlate the message with your records.

Expected result​

StepActionResult
1POST /whatsapp/templatesTemplate created with trackButtonLinks: true
2Meta approvalStatus APPROVED
3POST /whatsapp/sendMessage sent with tracked links
4Recipient clickEvent recorded + redirect to landing

Complete end-to-end example​

# 1. Create template with tracking (one-time, wait for approval)
curl -s -X POST "https://api.qlara.ai/api/message-server/whatsapp/templates?phoneNumberId=5" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "promo_estate_tracked_2026",
"lang": "it",
"category": "MARKETING",
"body": "Ciao {firstName}, sconto del 50% fino al 30 giugno!",
"buttons": [
{"type": "URL", "text": "Vai allo shop", "url": "https://shopitalia.it/promo?c=estate2026"}
],
"trackButtonLinks": true
}' | jq .

# 2. After approval, send the message (187 is the id returned in step 1)
MSG_ID=$(curl -s -X POST https://api.qlara.ai/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"phoneNumberId": 5,
"template": {"id": 187},
"placeholders": {"firstName": "Marco"}
}' | jq -r '.messageId')

echo "Message ID: $MSG_ID"

Variants​

Template with multiple tracked buttons​

Track clicks on multiple buttons to understand which CTA converts better:

curl -X POST "https://api.qlara.ai/api/message-server/whatsapp/templates?phoneNumberId=5" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "multi_cta_tracked_2026",
"lang": "it",
"category": "MARKETING",
"body": "Ciao {firstName}, scopri le nostre offerte!",
"buttons": [
{"type": "URL", "text": "Offerte donna", "url": "https://shop.it/donna?c=spring"},
{"type": "URL", "text": "Offerte uomo", "url": "https://shop.it/uomo?c=spring"}
],
"trackButtonLinks": true
}'

Every URL button is tracked on its own: originalButtonUrls lists the original URLs, with index 0 and 1.

Common errors​

400 Bad Request — Placeholder not allowed​

{
"status": "fail",
"data": {
"message": "INVALID_PLACEHOLDER",
"errors": ["percentualesconto"]
}
}

Solution: Placeholders must be contact fields of your account (such as {firstName} or {city}) or {shortLinkT1}–{shortLinkT4}. Write fixed values, such as the discount, straight into the text.

400 Bad Request — Invalid button URL​

{
"status": "fail",
"data": {
"message": "INVALID_BUTTON_URL",
"errors": ["The URL in the button is not valid."]
}
}

Solution: Meta rejected the URL of a button. Use a complete, valid URL, such as https://shopitalia.it/promo.

401 Unauthorized — Missing or invalid API Key​

The endpoint answers 401 with an empty body.

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

Next steps​

References​