Browse documentation

Webhooks

Webhook payload modes

Choose Yanola normalized events or a Meta-compatible payload shape for migration-oriented integrations.

DevelopersAdvancedAvailable

What this guide covers

  • Prefer normalized mode for stable Yanola public IDs and consistent envelopes.
  • Use Meta-compatible mode when adapting an existing direct Meta integration.
  • Treat compatibility as a payload shape option, not direct Meta delivery.

Choose one payload mode per endpoint

Yanola renders each delivery according to the endpoint's configured payload mode and identifies that format in yanola-payload-format. The event identity and delivery controls remain Yanola-managed in every mode.

Webhook payload modes
ModeBodyBest fit
yanolaStable Yanola Event envelope with normalized public data.New integrations and long-term Yanola contracts.
metaUnwrapped Meta-compatible WhatsApp webhook JSON shape.Migration of an existing Meta-shaped handler.
yanola_with_rawNormalized Event plus nullable retained provider payload.Audited integrations that explicitly need provider detail and accept retention limits.

Yanola-normalized payload

The yanola body is the same safe public Event envelope returned by client.events.retrieve. The data object can contain normalized message, Sender, and conversation projections.

yanola payload
json
{
  "id": "evt_...",
  "type": "whatsapp.message.received",
  "environment": "live",
  "createdAt": "2026-07-29T10:00:00.000Z",
  "data": {
    "message": {
      "id": "msg_...",
      "environment": "live",
      "direction": "inbound",
      "type": "text",
      "status": "delivered",
      "from": "+15551234567",
      "to": "+15557654321",
      "text": "Hello",
      "createdAt": "2026-07-29T10:00:00.000Z"
    },
    "sender": {
      "phoneNumber": "+15557654321",
      "displayName": "Acme Support",
      "status": "active",
      "apiEligible": true
    },
    "conversation": {
      "id": "conv_..."
    }
  }
}

Meta-compatible payload

The meta mode produces an unwrapped WhatsApp Business Account shape with object, entry, changes, and value. Yanola narrows a retained Meta batch to the triggering Developer Event when possible; otherwise it synthesizes the same structural shape from normalized data.

It is not a byte-for-byte replay of Meta's original HTTP request. Yanola still supplies its own signature and correlation headers, so continue verifying yanola-signature rather than a Meta signature header.

meta payload shape
json
{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "waba_...",
      "changes": [
        {
          "field": "messages",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "15557654321",
              "phone_number_id": "..."
            },
            "messages": []
          }
        }
      ]
    }
  ]
}

Normalized with retained raw data

yanola_with_raw adds a raw property to the normalized envelope. When retained data is available, raw contains provider, payloadType, and providerPayload.

raw is explicitly null when the provider payload was not retained or its entitlement-controlled retention window expired. Your handler must work correctly in both cases.

yanola_with_raw addition
json
{
  "id": "evt_...",
  "type": "whatsapp.message.received",
  "environment": "live",
  "createdAt": "2026-07-29T10:00:00.000Z",
  "data": {
    "message": {
      "id": "msg_..."
    }
  },
  "raw": {
    "provider": "meta_whatsapp",
    "payloadType": "webhook",
    "providerPayload": {}
  }
}

Use SDK payload types

The SDK exports WebhookPayload<'yanola'>, WebhookPayload<'meta'>, WebhookPayload<'yanola_with_raw'>, and their named component types. Validate runtime JSON before treating untrusted input as one of these TypeScript types.

Narrow by configured payload format
ts
import type {
  WebhookPayload,
  WebhookPayloadFormat,
} from "@yanola/whatsapp"

function handlePayload<Format extends WebhookPayloadFormat>(
  format: Format,
  payload: WebhookPayload<Format>
) {
  if (format === "yanola") {
    console.log((payload as WebhookPayload<"yanola">).id)
  }
}

Forward-compatible parsing

  1. Route by yanola-payload-format and, in normalized modes, by event.type.
  2. Ignore unknown additive normalized fields.
  3. Do not assume every event includes message, sender, and conversation simultaneously.
  4. Treat raw as nullable and providerPayload as untrusted unknown data.
  5. Do not infer environment or replay state from body shape; read the signed payload and Yanola headers.