---
title: "Send WhatsApp conversion event"
method: POST
path: "/v1/whatsapp/conversions"
tags: ["WhatsApp"]
---

# Send WhatsApp conversion event

`POST /v1/whatsapp/conversions`

Forward a WhatsApp Business Messaging conversion event (`LeadSubmitted`,
`Purchase`, `AddToCart`, `InitiateCheckout`, `ViewContent`) to Meta's
Conversions API with `action_source = business_messaging` and
`messaging_channel = whatsapp`. The endpoint looks up the originating
CTWA click ID (`ctwa_clid`) captured on the first inbound message of
the conversation and replays it on every event so Meta can attribute
the conversion back to the Click-to-WhatsApp ad that drove the chat.

Configuration prerequisite on the WhatsApp account metadata:
  - `metaCapiDatasetId`: the Meta dataset ID linked to the WABA.
    Provision one with `POST /v1/whatsapp/dataset`.

The WABA ID (already set automatically at connect time) is forwarded as
`user_data.whatsapp_business_account_id`, which is the per-channel
attribution identifier Meta requires for WhatsApp events. No Facebook
Page ID is needed (that field is the Messenger-branch identifier).

Identify the conversation by either `conversationId` (preferred) or
`phoneE164` (digits only, no `+`). At least one is required. If the
conversation has no captured `ctwa_clid`, the request returns 422
because there is nothing to attribute.

Token and dataset coupling: the WhatsApp account's accessToken must
have access to the configured `metaCapiDatasetId`. By default a WABA's
system-user token is scoped to the WABA's own Business Manager and
cannot post to a pixel owned by a different Business; Meta returns
code 100 in that case. Either share the dataset with the WhatsApp
app's Business in BM, or use a dataset already in the same Business
as the WABA.

## Request body

- object — In addition to the `required` list, at least one of `conversationId` or `phoneE164` must be supplied (used to resolve the originating CTWA conversation). The route enforces this at the Zod boundary; OpenAPI's `required` cannot express OR-required cleanly.
  - `accountId` string, required — WhatsApp SocialAccount ID.
  - `eventName` 'LeadSubmitted' | 'Purchase' | 'AddToCart' | 'InitiateCheckout' | 'ViewContent', required — Live-verified allowlist of event names accepted by Meta's CAPI for Business Messaging (Graph API v25.0). Other standard pixel events including `Lead`, `CompleteRegistration`, `Subscribe`, `Schedule`, `Contact`, `StartTrial`, `AddPaymentInfo`, `Search`, and `SubmitApplication` are rejected with subcode 2804066 ("Messaging Event Invalid Event Type") on `action_source = business_messaging` events. Custom event names are also rejected. Use `LeadSubmitted` (NOT `Lead`) for lead-style conversions.
  - `eventTime` number — Unix seconds. Defaults to the time of the request when omitted. Meta's attribution window is 7 days from click; events older than that lose attribution.
  - `eventId` string, required — Stable dedup key. Reuse to suppress duplicate events (Meta dedupes against pixel events with the same id).
  - `conversationId` string — Zernio Conversation `_id` (preferred lookup). The conversation must have a captured `ctwa_clid` in metadata (set automatically by the WhatsApp webhook on the first inbound message after a CTWA ad click).
  - `phoneE164` string — Contact phone number, digits only with no '+'. When used in lieu of `conversationId`, the handler resolves to the most recent CTWA-attributed conversation for this phone on the supplied account.
  - `value` number — Conversion value (e.g. order total).
  - `currency` string — ISO 4217 currency code (e.g. `USD`).
  - `contentIds` string[] — Optional product / content identifiers.
  - `email` string, email — User email. Normalized + SHA-256 hashed before sending to Meta.
  - `externalId` string — Stable customer identifier. Lowercased + SHA-256 hashed before sending to Meta.
  - `testCode` string — Meta `test_event_code` passthrough. Routes the event to the Test Events tab in Events Manager instead of the production dataset, useful for development.

## Response `200`

Event submitted to Meta. Inspect `eventsFailed` and `failures[]`
to detect partial failures. A 200 does not mean Meta accepted the
event; the status reflects "request reached Meta" only.

- object
  - `platform` 'metaads'
  - `eventsReceived` integer — Events accepted by Meta.
  - `eventsFailed` integer — Events rejected by Meta (see failures).
  - `failures` object[] — Per-event failure detail. Empty when all events were accepted.
    - `eventIndex` integer — Index into the submitted events array.
    - `eventId` string — Echoes back the eventId of the failed event.
    - `message` string
    - `code` union
      - string
      - integer
  - `traceId` string — Meta `fbtrace_id` for debugging. Surface in support tickets.

## Other responses

- `400` — Invalid body.
- `401` — Unauthorized
- `404` — Conversation not found.
- `422` — Configuration missing (no `metaCapiDatasetId` on the account, set it via POST /v1/whatsapp/dataset) OR the resolved conversation has no captured `ctwa_clid`.

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/versions/51932b099b2f/schema)
