← Blog

·

Click-to-WhatsApp ads: how to know which ad generated the sale

Updated on October 25, 2026

To know which Click-to-WhatsApp ad generated a sale, read the referral object the Cloud API sends in the incoming message webhook: it carries the ad ID (source_id) and a unique click ID (ctwa_clid). Store this data with the contact and conversation, and when the sale happens, link the order to it. That lets you compute sales per ad in your own system and also send the sale back to Meta through the Conversions API.

This guide shows the payload, what each field means, how to build attribution in your database, how to check the free entry point window through the status webhook, and the cases where the data doesn’t arrive.

What a Click-to-WhatsApp ad is

Click-to-WhatsApp (CTWA) ads are Facebook and Instagram ads whose button opens a chat with the business on WhatsApp. The person taps the ad, WhatsApp opens with a pre-filled message and, when they send it, your integration receives that message through the webhook with the ad data attached.

The key point: Ads Manager shows how many conversations an ad started, but it doesn’t know what happened next. The sale closes in the chat, in your CRM or at your checkout. Your integration is what connects both ends.

The referral object in the webhook

According to the text messages webhook reference, when a message comes from a CTWA ad, it arrives with a referral object:

{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WABA_ID",
    "changes": [{
      "field": "messages",
      "value": {
        "messaging_product": "whatsapp",
        "metadata": { "display_phone_number": "5511999990000", "phone_number_id": "PHONE_NUMBER_ID" },
        "contacts": [{ "profile": { "name": "Ana" }, "wa_id": "5511988887777" }],
        "messages": [{
          "from": "5511988887777",
          "id": "wamid.HBgN...",
          "timestamp": "1761400000",
          "type": "text",
          "text": { "body": "Hi! I'd like to know more about the annual plan." },
          "referral": {
            "source_url": "https://fb.me/3cr4Wqqkv",
            "source_id": "120226305854810726",
            "source_type": "ad",
            "headline": "Chat with us",
            "body": "Annual plan with WhatsApp support",
            "media_type": "image",
            "image_url": "https://scontent.xx.fbcdn.net/...",
            "ctwa_clid": "Aff-n8ZTODiE79d22KtAwQKj9e_mIEOOj27vDVwFjN80dp4...",
            "welcome_message": { "text": "Hi there! How can we help?" }
          }
        }]
      }
    }]
  }]
}

What each field means

FieldWhat it isUse in attribution
source_idAd IDKey to group sales by ad
source_typeSource (ad for ads)Filter what came from ads
source_urlAd URLReference to check on Facebook
headline / bodyAd headline and primary textIdentify the creative without calling the Marketing API
media_typeimage or videoCompare formats
image_url, video_url, thumbnail_urlAd media (depending on type)Show the creative in your CRM
ctwa_clidClick ID, unique per clickSend the conversion back to Meta
welcome_message.textAd greeting textContext for your support team

Two notes from Meta’s documentation:

  • The ctwa_clid is omitted when the message comes from an ad in WhatsApp Status. You still get the source_id.
  • The ctwa_clid is a personal identifier, unique per click, according to the Conversions API for Business Messaging guide. Treat it as personal data, with the same protection as the customer’s phone number.

How to build attribution in your system

The logic is simple: store the click when it arrives, and link the sale to the click when it happens.

1. Store the referral as soon as the message arrives

Create a conversation source table:

CREATE TABLE conversation_source (
  id            BIGSERIAL PRIMARY KEY,
  wa_id         TEXT NOT NULL,
  wamid         TEXT NOT NULL UNIQUE,
  ad_id         TEXT,
  ctwa_clid     TEXT,
  headline      TEXT,
  received_at   TIMESTAMPTZ NOT NULL
);

And in the webhook handler:

export function recordSource(value, db) {
  for (const msg of value.messages ?? []) {
    const ref = msg.referral;
    if (!ref || ref.source_type !== 'ad') continue;

    db.insertSource({
      wa_id: msg.from,
      wamid: msg.id,
      ad_id: ref.source_id,
      ctwa_clid: ref.ctwa_clid ?? null, // missing for Status ads
      headline: ref.headline ?? null,
      received_at: new Date(Number(msg.timestamp) * 1000),
    });
  }
}

Use the wamid as a unique key: Meta may resend the same webhook, and the UNIQUE constraint prevents duplicate sources. To test with sample payloads before running ads, see how to test the webhook locally.

2. Link the sale to the last click

When the order is created (at checkout, in the CRM or by an agent), look up the latest source for that wa_id within a window you choose, for example 7 or 28 days:

SELECT ad_id, ctwa_clid
FROM conversation_source
WHERE wa_id = $1
  AND received_at >= now() - interval '7 days'
ORDER BY received_at DESC
LIMIT 1;

Save ad_id and ctwa_clid on the order. This is your last-click model. If someone clicked two ads, the sale goes to the most recent one. Choose the window based on your sales cycle and keep the same rule when comparing ads.

If the sale happens at a checkout outside WhatsApp, include a contact identifier in the link you send in the chat (an order or session code), so the checkout can map back to the wa_id.

3. Put names on the IDs

The source_id is a number. To show “Black Friday campaign – Video 2” in your report, query the Marketing API with a token that has access to the ad account:

curl "https://graph.facebook.com/v26.0/120226305854810726?fields=name,adset{name},campaign{name}&access_token=TOKEN_WITH_ADS_READ"

Cache the result: ad names rarely change, and querying on every message is wasteful.

4. Report by ad

With ad_id on the order, the report is a query: conversations per ad (from the source table), orders and revenue per ad (from the orders table), and the conversion rate between them. Add each ad’s spend, exported from Ads Manager, and you get cost per sale.

The free entry point window

Conversations that start from a CTWA ad come with a cost benefit. According to Meta’s pricing page, if a user messages you from a CTWA ad on the Android or iOS app and the business replies within the customer service window, that reply isn’t charged and opens a free entry point (FEP) window. While it’s open, marketing, utility, authentication and service messages aren’t charged. Meta Business Agent messages are still charged.

Official sources disagree on the duration: the developer documentation says the window may stay open for up to 7 days, while the WhatsApp Business marketing site still says 72 hours. Instead of relying on a fixed number, check the status webhook. According to the status reference, messages sent inside the free window arrive with pricing.type set to free_entry_point. The same reference lists the referral_conversion category for free entry point conversations:

{
  "id": "wamid.HBgN...",
  "status": "delivered",
  "recipient_id": "5511988887777",
  "pricing": {
    "pricing_model": "PMP",
    "type": "free_entry_point",
    "category": "referral_conversion"
  }
}

Recording the pricing of every message lets you add to your report how much you saved on messages per ad. See the message status webhook.

Two practical consequences:

  • Reply fast. The free window only opens if the business replies within the customer service window. An automatic welcome message solves that.
  • Concentrate your follow-up. Reminders and offers sent inside the free window don’t pay the marketing rate. It’s a good moment for PIX and cart recovery (PIX is Brazil’s instant payment system).

When the referral doesn’t arrive

SituationWhat happensWhat to do
Ad shown in WhatsApp Statusreferral arrives, without ctwa_clidAttribute by source_id
Customer saves the number and writes days later, outside the adRegular message, no referralCount the conversation as organic in your system
Webhook down when the message arrivedData is lost if you don’t process the retryReturn 200 quickly and process in a queue
Desktop or web appThe free window doesn’t apply (the pricing page only mentions Android and iOS)Don’t count on free messages in these cases

From reporting to optimization: the Conversions API

Knowing which ad sells is half the job. The other half is telling Meta, so ad delivery learns from sales and not just from started conversations. You do that by sending events (such as Purchase) with the ctwa_clid to the Conversions API. The step-by-step is in Meta Conversions API for WhatsApp.

How to do it with Vectalk

Vectalk forwards webhooks in Meta’s format, so the referral object reaches your URL exactly as described above, with no conversion. To get started:

  1. Connect your number at apps.vectalk.com.br/register.
  2. Register your webhook with POST /api/webhooks (docs). You can register more than one URL per instance, for example one for support and another only for the attribution service.
  3. Store referral and pricing as shown in this article.

Frequently asked questions

Does the referral come with every message in the conversation?

Meta’s documentation describes the referral on the message the user sends from the ad. Store it as soon as it arrives and don’t rely on receiving it again in later messages.

What’s the difference between source_id and ctwa_clid?

The source_id is the ad ID: the same for everyone who clicked that ad. The ctwa_clid is the ID of one specific click by one person. For per-ad reporting, use source_id; to send the conversion back to Meta, use ctwa_clid.

Can I get the campaign and ad set?

Yes, by querying the ad ID in the Marketing API with a token that has access to the ad account. The WhatsApp webhook only carries the ad ID and the creative’s text.

Is the free window 72 hours or 7 days?

Meta’s developer documentation says up to 7 days; the WhatsApp Business marketing site still says 72 hours. Check message by message through pricing.type in the status webhook: free_entry_point means the message wasn’t charged because it was inside the window.

Does it work with Instagram ads?

Yes. Click-to-WhatsApp ads can run on Facebook and Instagram, and the message reaches WhatsApp with the referral in the same way.


Official sources checked on October 25, 2026: Text messages webhook (referral), Status webhook (pricing), Platform pricing, Pricing on the WhatsApp Business site, Conversions API for Business Messaging, CTWA welcome message sequences, Vectalk: webhooks.

Integre o WhatsApp oficial ao seu sistema

A Vectalk entrega a Cloud API da Meta com os mesmos payloads e webhooks, um token para todas as contas e documentação completa.