> ## Documentation Index
> Fetch the complete documentation index at: https://docs.connectly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversion Reporting

> Report WhatsApp-attributed purchases and product views to Meta's Conversions API via Connectly 🧾

When a customer clicks a Click-to-WhatsApp (CTWA) ad and later purchases on your site, Connectly can forward that conversion event to Meta's Conversions API on your behalf — so the originating ad gets credit in Ads Manager. You send the event to Connectly; you never need to talk to Meta directly.

## Endpoint

```json theme={null}
POST https://api.connectly.ai/external/v1/businesses/{business_id}/conversion_events
```

## Integration journey

<Steps>
  <Step title="Get your API key">
    Open the Connectly inbox → **Settings** → **General** → **API Key**. Create a new key with all scopes unchecked (full access) or reuse an existing one if you still have the plaintext. The key is shown only once — copy and store it securely. Never expose it client-side or commit it to source control.
  </Step>

  <Step title="Enable purchase tracking in your campaign">
    In the Flow Builder, open the **Audience** step of your Click-to-WhatsApp card and tick **"Track purchases completed on my own site and report them to the Ads Manager"**. Without this, carousel CTA links will not carry the required tracking parameters.
  </Step>

  <Step title="Capture tracking parameters at landing">
    Once your campaign sends, Connectly auto-appends five query parameters to every CTA link:

    ```text theme={null}
    ?cnct_tracking_id=<value>&sendout_id=<value>&ctwa_clid=<value>&ad_id=<value>&attribution_source=meta_ctwa
    ```

    Persist all five values when the customer lands on your site — store them in the session or against the customer record — so they're available at checkout.
  </Step>

  <Step title="Call the conversion endpoint on purchase">
    When the customer completes a purchase, POST a single conversion event to Connectly with the tracking parameters captured at landing.
  </Step>

  <Step title="Verify in Ads Manager">
    Connectly forwards the event to Meta. Conversions typically appear in Meta Events Manager and roll up into Ads Manager attribution within a few hours.
  </Step>
</Steps>

***

## Request body

### Top-level fields

<ParamField body="cnct_tracking_id" type="string" required>
  Verbatim copy of the `cnct_tracking_id` query parameter from the landing URL. Identifies the originating WhatsApp/CTWA session at the customer level.
</ParamField>

<ParamField body="event_name" type="string" required>
  Meta CAPI event name. Accepted values: `"Purchase"` or `"ViewContent"`. Any other value returns `400 INVALID_ARGUMENT`.
</ParamField>

<ParamField body="sendout_id" type="string" required>
  Verbatim copy of the `sendout_id` query parameter from the landing URL. Credits the conversion to the correct Connectly campaign.
</ParamField>

<ParamField body="attribution" type="object" required>
  CTWA attribution data.

  <Expandable title="attribution fields">
    <ParamField body="attribution.meta_ctwa.ctwa_clid" type="string" required>
      Verbatim copy of the `ctwa_clid` query parameter from the landing URL. Forwarded to Meta CAPI as `user_data.ctwa_clid` to credit the originating ad.
    </ParamField>

    <ParamField body="attribution.meta_ctwa.ad_id" type="string" required>
      Verbatim copy of the `ad_id` query parameter from the landing URL. Used in Connectly's per-ad conversion analytics — not forwarded to Meta CAPI directly.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="payload" type="object" required>
  Per-event detail. For `Purchase`, `currency` and `value` are required.

  <Expandable title="payload fields">
    <ParamField body="payload.currency" type="string" required>
      ISO 4217 currency code (e.g. `"USD"`, `"BRL"`, `"MXN"`). Required for `Purchase`.
    </ParamField>

    <ParamField body="payload.value" type="number" required>
      Total order value as a decimal (e.g. `99.97`). Must be ≥ 0. Required for `Purchase`.
    </ParamField>

    <ParamField body="payload.order_id" type="string">
      Your internal order reference. Strongly recommended — Connectly passes this to Meta as the `event_id` deduplication key so the CAPI event and your browser pixel don't double-count the same purchase. Keep it stable per order; the request is safe to retry.
    </ParamField>

    <ParamField body="payload.content_type" type="string">
      `"product"` for SKU-level catalog matching, or `"product_group"` for group-level.
    </ParamField>

    <ParamField body="payload.content_ids" type="string[]">
      Array of SKU or product IDs matching your Meta product catalog. Max 100 items.
    </ParamField>

    <ParamField body="payload.num_items" type="integer">
      Total cart size — sum of `contents[].quantity`.
    </ParamField>

    <ParamField body="payload.contents" type="object[]">
      Per-line-item detail. Preferred over `content_ids` alone when quantity matters. Max 100 items.

      <Expandable title="contents[] fields">
        <ParamField body="id" type="string" required>
          SKU or product ID matching your Meta catalog. Items without an `id` are silently skipped.
        </ParamField>

        <ParamField body="quantity" type="integer">
          Units of this item. Without it, multi-item orders appear as single-item orders to Meta's bid optimizer.
        </ParamField>

        <ParamField body="item_price" type="number">
          Per-unit price. Enables Meta to compute revenue per item for value-based bidding.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="payload.event_time" type="integer">
      Unix epoch timestamp (seconds) of when the order occurred. Defaults to receive-time if omitted. Important for batched or backfilled events — Meta rejects events older than 7 days.
    </ParamField>
  </Expandable>
</ParamField>

***

## Example request

```bash theme={null}
curl -i -X POST "https://api.connectly.ai/external/v1/businesses/<BUSINESS_ID>/conversion_events" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: <YOUR_API_KEY>" \
  -d '{
    "cnct_tracking_id": "<value from URL>",
    "event_name": "Purchase",
    "sendout_id": "<value from URL>",
    "attribution": {
      "meta_ctwa": {
        "ctwa_clid": "<value from URL>",
        "ad_id": "<value from URL>"
      }
    },
    "payload": {
      "currency": "USD",
      "value": 99.97,
      "order_id": "ORD-7821",
      "content_type": "product",
      "content_ids": ["sku-1", "sku-2"],
      "num_items": 2,
      "contents": [
        { "id": "sku-1", "quantity": 1, "item_price": 49.99 },
        { "id": "sku-2", "quantity": 1, "item_price": 49.98 }
      ],
      "event_time": 1746480000
    }
  }'
```

## Response

```json theme={null}
{ "events_received": 1 }
```

`events_received: 1` confirms Connectly received and recorded the event. Connectly logs the conversion to your campaign analytics regardless of whether the Meta CAPI forward succeeds. If Meta rejects the event, you receive a non-200 response with Meta's verbatim error message.

***

## Error responses

| HTTP status            | When                                                                                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400 INVALID_ARGUMENT` | Missing or invalid required fields; missing `currency`/`value` for a `Purchase` event; unsupported `event_name`; or Meta rejected the forwarded event. |
| `401 Unauthenticated`  | Missing or invalid `X-API-KEY`.                                                                                                                        |
| `404 NOT_FOUND`        | Business not found, or the business has no WhatsApp Cloud channel configured.                                                                          |

***

## Notes

<Note>
  Send **one event per API call**. For multi-item orders, include all items in the `contents[]` array within a single `Purchase` event — do not send multiple POST requests for the same order.
</Note>

* `cnct_tracking_id`, `sendout_id`, `ctwa_clid`, and `ad_id` must be captured from the landing page URL at visit time and passed back when the customer converts — which may happen later in the same session.
* Set `event_time` to the actual order timestamp, not the time you call the API. This matters if you flush events in batches or run backfills.
* `order_id` doubles as Meta's dedup key — keep it stable per order so retries are safe.

<Steps>
  <Step title="Get your API key">
    Open the Connectly inbox → **Settings** → **General** → **API Key**. Create a new key with all scopes unchecked (full access) or reuse an existing one if you still have the plaintext. The key is shown only once — copy and store it securely. Never expose it client-side or commit it to source control.
  </Step>

  <Step title="Enable purchase tracking in your campaign">
    In the Flow Builder, open the **Audience** step of your Click-to-WhatsApp card and tick **"Track purchases completed on my own site and report them to the Ads Manager"**. Without this, carousel CTA links will not carry the required tracking parameters.
  </Step>

  <Step title="Capture tracking parameters at landing">
    Once your campaign sends, Connectly auto-appends five query parameters to every CTA link:

    ```text theme={null}
    ?cnct_tracking_id=<value>&sendout_id=<value>&ctwa_clid=<value>&ad_id=<value>&attribution_source=meta_ctwa
    ```

    Persist all five values when the customer lands on your site — store them in the session or against the customer record — so they're available at checkout.
  </Step>

  <Step title="Call the conversion endpoint on purchase">
    When the customer completes a purchase, POST a single conversion event to Connectly with the tracking parameters captured at landing.
  </Step>

  <Step title="Verify in Ads Manager">
    Connectly forwards the event to Meta. Conversions typically appear in Meta Events Manager and roll up into Ads Manager attribution within a few hours.
  </Step>
</Steps>

***

## Request body

<ParamField body="cnct_tracking_id" type="string" required>
  Verbatim copy of the `cnct_tracking_id` query parameter from the landing URL. Identifies the originating WhatsApp/CTWA session at the customer level.
</ParamField>

<ParamField body="event_name" type="string" required>
  Meta CAPI event name. Accepted values: `"Purchase"` or `"ViewContent"`. Any other value returns `400 INVALID_ARGUMENT`.
</ParamField>

<ParamField body="sendout_id" type="string" required>
  Verbatim copy of the `sendout_id` query parameter from the landing URL. Credits the conversion to the correct Connectly campaign.
</ParamField>

<ParamField body="attribution" type="object" required>
  CTWA attribution data.

  <Expandable title="attribution fields">
    <ParamField body="attribution.meta_ctwa.ctwa_clid" type="string" required>
      Verbatim copy of the `ctwa_clid` query parameter from the landing URL. Forwarded to Meta CAPI as `user_data.ctwa_clid` to credit the originating ad.
    </ParamField>

    <ParamField body="attribution.meta_ctwa.ad_id" type="string" required>
      Verbatim copy of the `ad_id` query parameter from the landing URL. Used in Connectly's per-ad conversion analytics — not forwarded to Meta CAPI directly.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="payload" type="object" required>
  Per-event detail. For `Purchase`, `currency` and `value` are required.

  <Expandable title="payload fields">
    <ParamField body="payload.currency" type="string" required>
      ISO 4217 currency code (e.g. `"USD"`, `"BRL"`, `"MXN"`). Required for `Purchase`.
    </ParamField>

    <ParamField body="payload.value" type="number" required>
      Total order value as a decimal (e.g. `99.97`). Must be ≥ 0. Required for `Purchase`.
    </ParamField>

    <ParamField body="payload.order_id" type="string">
      Your internal order reference. Strongly recommended — Connectly passes this to Meta as the `event_id` deduplication key so the CAPI event and your browser pixel don't double-count the same purchase. Keep it stable per order; the request is safe to retry.
    </ParamField>

    <ParamField body="payload.content_type" type="string">
      `"product"` for SKU-level catalog matching, or `"product_group"` for group-level.
    </ParamField>

    <ParamField body="payload.content_ids" type="string[]">
      Array of SKU or product IDs matching your Meta product catalog. Max 100 items.
    </ParamField>

    <ParamField body="payload.num_items" type="integer">
      Total cart size — sum of `contents[].quantity`.
    </ParamField>

    <ParamField body="payload.contents" type="object[]">
      Per-line-item detail. Preferred over `content_ids` alone when quantity matters. Max 100 items.

      <Expandable title="contents[] fields">
        <ParamField body="id" type="string" required>
          SKU or product ID matching your Meta catalog. Items without an `id` are silently skipped.
        </ParamField>

        <ParamField body="quantity" type="integer">
          Units of this item. Without it, multi-item orders appear as single-item orders to Meta's bid optimizer.
        </ParamField>

        <ParamField body="item_price" type="number">
          Per-unit price. Enables Meta to compute revenue per item for value-based bidding.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="payload.event_time" type="integer">
      Unix epoch timestamp (seconds) of when the order occurred. Defaults to receive-time if omitted. Important for batched or backfilled events — Meta rejects events older than 7 days.
    </ParamField>
  </Expandable>
</ParamField>

***

```bash theme={null}
curl -i -X POST "https://api.connectly.ai/external/v1/businesses/<BUSINESS_ID>/conversion_events" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: <YOUR_API_KEY>" \
  -d '{
    "cnct_tracking_id": "<value from URL>",
    "event_name": "Purchase",
    "sendout_id": "<value from URL>",
    "attribution": {
      "meta_ctwa": {
        "ctwa_clid": "<value from URL>",
        "ad_id": "<value from URL>"
      }
    },
    "payload": {
      "currency": "USD",
      "value": 99.97,
      "order_id": "ORD-7821",
      "content_type": "product",
      "content_ids": ["sku-1", "sku-2"],
      "num_items": 2,
      "contents": [
        { "id": "sku-1", "quantity": 1, "item_price": 49.99 },
        { "id": "sku-2", "quantity": 1, "item_price": 49.98 }
      ],
      "event_time": 1746480000
    }
  }'
```

`events_received: 1` confirms Connectly received and recorded the event. Connectly logs the conversion to your campaign analytics regardless of whether the Meta CAPI forward succeeds. If Meta rejects the event, you receive a non-200 response with Meta's verbatim error message.

***

## Error responses

| HTTP status            | When                                                                                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400 INVALID_ARGUMENT` | Missing or invalid required fields; missing `currency`/`value` for a `Purchase` event; unsupported `event_name`; or Meta rejected the forwarded event. |
| `401 Unauthenticated`  | Missing or invalid `X-API-KEY`.                                                                                                                        |
| `404 NOT_FOUND`        | Business not found, or the business has no WhatsApp Cloud channel configured.                                                                          |

***

<Note>
  Send **one event per API call**. For multi-item orders, include all items in the `contents[]` array within a single `Purchase` event — do not send multiple POST requests for the same order.
</Note>

* `cnct_tracking_id`, `sendout_id`, `ctwa_clid`, and `ad_id` must be captured from the landing page URL at visit time and passed back when the customer converts — which may happen later in the same session.
* Set `event_time` to the actual order timestamp, not the time you call the API. This matters if you flush events in batches or run backfills.
* `order_id` doubles as Meta's dedup key — keep it stable per order so retries are safe.

<Steps>
  <Step title="Get your API key">
    Open the Connectly inbox → **Settings** → **General** → **API Key**. Create a new key with all scopes unchecked (full access) or reuse an existing one if you still have the plaintext. The key is shown only once — copy and store it securely. Never expose it client-side or commit it to source control.
  </Step>

  <Step title="Enable purchase tracking in your campaign">
    In the Flow Builder, open the **Audience** step of your Click-to-WhatsApp card and tick **"Track purchases completed on my own site and report them to the Ads Manager"**. Without this, carousel CTA links will not carry the required tracking parameters.
  </Step>

  <Step title="Capture tracking parameters at landing">
    Once your campaign sends, Connectly auto-appends five query parameters to every CTA link:

    ```text theme={null}
    ?cnct_tracking_id=<value>&sendout_id=<value>&ctwa_clid=<value>&ad_id=<value>&attribution_source=meta_ctwa
    ```

    Persist all five values when the customer lands on your site — store them in the session or against the customer record — so they're available at checkout.
  </Step>

  <Step title="Call the conversion endpoint on purchase">
    When the customer completes a purchase, POST a single conversion event to Connectly with the tracking parameters captured at landing.
  </Step>

  <Step title="Verify in Ads Manager">
    Connectly forwards the event to Meta. Conversions typically appear in Meta Events Manager and roll up into Ads Manager attribution within a few hours.
  </Step>
</Steps>

***

## Request body

<ParamField body="cnct_tracking_id" type="string" required>
  Verbatim copy of the `cnct_tracking_id` query parameter from the landing URL. Identifies the originating WhatsApp/CTWA session at the customer level.
</ParamField>

<ParamField body="event_name" type="string" required>
  Meta CAPI event name. Accepted values: `"Purchase"` or `"ViewContent"`. Any other value returns `400 INVALID_ARGUMENT`.
</ParamField>

<ParamField body="sendout_id" type="string" required>
  Verbatim copy of the `sendout_id` query parameter from the landing URL. Credits the conversion to the correct Connectly campaign.
</ParamField>

<ParamField body="attribution" type="object" required>
  CTWA attribution data.

  <Expandable title="attribution fields">
    <ParamField body="attribution.meta_ctwa.ctwa_clid" type="string" required>
      Verbatim copy of the `ctwa_clid` query parameter from the landing URL. Forwarded to Meta CAPI as `user_data.ctwa_clid` to credit the originating ad.
    </ParamField>

    <ParamField body="attribution.meta_ctwa.ad_id" type="string" required>
      Verbatim copy of the `ad_id` query parameter from the landing URL. Used in Connectly's per-ad conversion analytics — not forwarded to Meta CAPI directly.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="payload" type="object" required>
  Per-event detail. For `Purchase`, `currency` and `value` are required.

  <Expandable title="payload fields">
    <ParamField body="payload.currency" type="string" required>
      ISO 4217 currency code (e.g. `"USD"`, `"BRL"`, `"MXN"`). Required for `Purchase`.
    </ParamField>

    <ParamField body="payload.value" type="number" required>
      Total order value as a decimal (e.g. `99.97`). Must be ≥ 0. Required for `Purchase`.
    </ParamField>

    <ParamField body="payload.order_id" type="string">
      Your internal order reference. Strongly recommended — Connectly passes this to Meta as the `event_id` deduplication key so the CAPI event and your browser pixel don't double-count the same purchase. Keep it stable per order; the request is safe to retry.
    </ParamField>

    <ParamField body="payload.content_type" type="string">
      `"product"` for SKU-level catalog matching, or `"product_group"` for group-level.
    </ParamField>

    <ParamField body="payload.content_ids" type="string[]">
      Array of SKU or product IDs matching your Meta product catalog. Max 100 items.
    </ParamField>

    <ParamField body="payload.num_items" type="integer">
      Total cart size — sum of `contents[].quantity`.
    </ParamField>

    <ParamField body="payload.contents" type="object[]">
      Per-line-item detail. Preferred over `content_ids` alone when quantity matters. Max 100 items.

      <Expandable title="contents[] fields">
        <ParamField body="id" type="string" required>
          SKU or product ID matching your Meta catalog. Items without an `id` are silently skipped.
        </ParamField>

        <ParamField body="quantity" type="integer">
          Units of this item. Without it, multi-item orders appear as single-item orders to Meta's bid optimizer.
        </ParamField>

        <ParamField body="item_price" type="number">
          Per-unit price. Enables Meta to compute revenue per item for value-based bidding.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="payload.event_time" type="integer">
      Unix epoch timestamp (seconds) of when the order occurred. Defaults to receive-time if omitted. Important for batched or backfilled events — Meta rejects events older than 7 days.
    </ParamField>
  </Expandable>
</ParamField>

***

```bash theme={null}
curl -i -X POST "https://api.connectly.ai/external/v1/businesses/<BUSINESS_ID>/conversion_events" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: <YOUR_API_KEY>" \
  -d '{
    "cnct_tracking_id": "<value from URL>",
    "event_name": "Purchase",
    "sendout_id": "<value from URL>",
    "attribution": {
      "meta_ctwa": {
        "ctwa_clid": "<value from URL>",
        "ad_id": "<value from URL>"
      }
    },
    "payload": {
      "currency": "USD",
      "value": 99.97,
      "order_id": "ORD-7821",
      "content_type": "product",
      "content_ids": ["sku-1", "sku-2"],
      "num_items": 2,
      "contents": [
        { "id": "sku-1", "quantity": 1, "item_price": 49.99 },
        { "id": "sku-2", "quantity": 1, "item_price": 49.98 }
      ],
      "event_time": 1746480000
    }
  }'
```

`events_received: 1` confirms Connectly received and recorded the event. Connectly logs the conversion to your campaign analytics regardless of whether the Meta CAPI forward succeeds. If Meta rejects the event, you receive a non-200 response with Meta's verbatim error message.

***

## Error responses

| HTTP status            | When                                                                                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400 INVALID_ARGUMENT` | Missing or invalid required fields; missing `currency`/`value` for a `Purchase` event; unsupported `event_name`; or Meta rejected the forwarded event. |
| `401 Unauthenticated`  | Missing or invalid `X-API-KEY`.                                                                                                                        |
| `404 NOT_FOUND`        | Business not found, or the business has no WhatsApp Cloud channel configured.                                                                          |

***

<Note>
  Send **one event per API call**. For multi-item orders, include all items in the `contents[]` array within a single `Purchase` event — do not send multiple POST requests for the same order.
</Note>

* `cnct_tracking_id`, `sendout_id`, `ctwa_clid`, and `ad_id` must be captured from the landing page URL at visit time and passed back when the customer converts — which may happen later in the same session.
* Set `event_time` to the actual order timestamp, not the time you call the API. This matters if you flush events in batches or run backfills.
* `order_id` doubles as Meta's dedup key — keep it stable per order so retries are safe.
