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

# Incoming Message Events

> Full payload reference for every message type a user can send to your WhatsApp number.

When a user sends a message to your WhatsApp number, the Connexease Gateway receives the event from Meta and forwards it to your registered webhook URL. The top-level envelope is always the same — `entry[0].changes[0].value` — but the inner shape depends on what the user sent. This page is the complete reference for every incoming message type, with field descriptions for each.

***

## Envelope Structure

Every incoming message arrives wrapped in this envelope:

```json theme={null}
{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WABA_ID_123456",
    "changes": [{
      "field": "messages",
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "905321234567",
          "phone_number_id": "PHONE_NUMBER_ID_123"
        },
        "contacts": [{
          "profile": { "name": "John Smith" },
          "wa_id": "905399876543"
        }],
        "messages": [{ "...message object..." }]
      }
    }]
  }]
}
```

**Envelope Fields:**

| Field                                 | Type   | Description                                           |
| ------------------------------------- | ------ | ----------------------------------------------------- |
| `entry[0].id`                         | string | Your WhatsApp Business Account (WABA) ID              |
| `value.metadata.phone_number_id`      | string | Meta ID of the phone number that received the message |
| `value.metadata.display_phone_number` | string | Human-readable phone number                           |
| `value.contacts[0].wa_id`             | string | Sender's WhatsApp phone number                        |
| `value.contacts[0].profile.name`      | string | Sender's WhatsApp display name                        |
| `value.messages[0]`                   | object | The message object — structure varies by type         |

***

## Common Message Fields

Every message object, regardless of type, contains:

| Field       | Type   | Description                                         |
| ----------- | ------ | --------------------------------------------------- |
| `from`      | string | Sender's phone number (same as `contacts[0].wa_id`) |
| `id`        | string | Unique incoming message ID (`wamid`)                |
| `timestamp` | string | Unix timestamp in seconds                           |
| `type`      | string | Message type — see sections below                   |

***

## Message Types

<AccordionGroup>
  <Accordion title="Text Message">
    Received when a user sends a plain text message.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.HBgNOTA1Mzk5ODc2NTQzFQIAERgSM0Y3RDg5NjREOUNBMkFFNEE3AA==",
      "timestamp": "1711900000",
      "type": "text",
      "text": {
        "body": "Hello, I'd like to know the status of my order."
      }
    }
    ```

    | Field       | Type   | Description                     |
    | ----------- | ------ | ------------------------------- |
    | `text.body` | string | The text content of the message |
  </Accordion>

  <Accordion title="Image Message">
    Received when a user sends a photo. The image content must be downloaded via the Media API using `image.id`.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900050",
      "type": "image",
      "image": {
        "caption": "Here is the damaged item",
        "mime_type": "image/jpeg",
        "sha256": "abc123...",
        "id": "MEDIA_ID_789"
      }
    }
    ```

    | Field             | Type   | Description                                                 |
    | ----------------- | ------ | ----------------------------------------------------------- |
    | `image.id`        | string | Media ID — use this to download the image via the Media API |
    | `image.mime_type` | string | `image/jpeg` or `image/png`                                 |
    | `image.sha256`    | string | SHA-256 hash for integrity verification                     |
    | `image.caption`   | string | Caption written by the user (optional)                      |

    <Note>
      See the [Media](/api-reference/media) page for how to download the file using `image.id`.
    </Note>
  </Accordion>

  <Accordion title="Audio Message">
    Received when a user sends an audio file or records a voice note.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900100",
      "type": "audio",
      "audio": {
        "mime_type": "audio/ogg; codecs=opus",
        "sha256": "def456...",
        "id": "MEDIA_ID_456",
        "voice": true
      }
    }
    ```

    | Field             | Type    | Description                                                |
    | ----------------- | ------- | ---------------------------------------------------------- |
    | `audio.id`        | string  | Media ID for downloading the audio                         |
    | `audio.voice`     | boolean | `true` = user recorded a voice note; `false` = file upload |
    | `audio.mime_type` | string  | `audio/ogg; codecs=opus`, `audio/mp4`, `audio/mpeg`, etc.  |
    | `audio.sha256`    | string  | SHA-256 hash for integrity verification                    |
  </Accordion>

  <Accordion title="Document Message">
    Received when a user sends a PDF, Word document, or other file.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900150",
      "type": "document",
      "document": {
        "caption": "Invoice",
        "filename": "invoice_march_2025.pdf",
        "mime_type": "application/pdf",
        "sha256": "ghi789...",
        "id": "MEDIA_ID_321"
      }
    }
    ```

    | Field                | Type   | Description                               |
    | -------------------- | ------ | ----------------------------------------- |
    | `document.id`        | string | Media ID for downloading the document     |
    | `document.filename`  | string | Original filename as uploaded by the user |
    | `document.mime_type` | string | MIME type of the file                     |
    | `document.caption`   | string | Caption written by the user (optional)    |
  </Accordion>

  <Accordion title="Video Message">
    Received when a user sends a video file.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900200",
      "type": "video",
      "video": {
        "caption": "Screen recording of the issue",
        "mime_type": "video/mp4",
        "sha256": "jkl012...",
        "id": "MEDIA_ID_654"
      }
    }
    ```

    | Field             | Type   | Description                            |
    | ----------------- | ------ | -------------------------------------- |
    | `video.id`        | string | Media ID for downloading the video     |
    | `video.mime_type` | string | `video/mp4` or `video/3gp`             |
    | `video.caption`   | string | Caption written by the user (optional) |
  </Accordion>

  <Accordion title="Sticker Message">
    Received when a user sends a WhatsApp sticker.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900250",
      "type": "sticker",
      "sticker": {
        "mime_type": "image/webp",
        "sha256": "mno345...",
        "id": "MEDIA_ID_987",
        "animated": false
      }
    }
    ```

    | Field               | Type    | Description                          |
    | ------------------- | ------- | ------------------------------------ |
    | `sticker.id`        | string  | Media ID for downloading the sticker |
    | `sticker.animated`  | boolean | `true` = animated sticker            |
    | `sticker.mime_type` | string  | Always `image/webp`                  |
  </Accordion>

  <Accordion title="Location Message">
    Received when a user shares their location.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900300",
      "type": "location",
      "location": {
        "latitude": 41.0082376,
        "longitude": 28.9783589,
        "name": "Taksim Square",
        "address": "Taksim, Istanbul"
      }
    }
    ```

    | Field                | Type   | Description                        |
    | -------------------- | ------ | ---------------------------------- |
    | `location.latitude`  | number | Latitude coordinate                |
    | `location.longitude` | number | Longitude coordinate               |
    | `location.name`      | string | Place name (optional, set by user) |
    | `location.address`   | string | Full address (optional)            |
  </Accordion>

  <Accordion title="Contact Message">
    Received when a user shares a contact card.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900350",
      "type": "contacts",
      "contacts": [{
        "name": {
          "formatted_name": "Jane Doe",
          "first_name": "Jane",
          "last_name": "Doe"
        },
        "phones": [
          { "phone": "+905321234567", "type": "CELL" }
        ],
        "emails": [
          { "email": "jane@example.com", "type": "WORK" }
        ]
      }]
    }
    ```

    | Field                            | Type   | Description                     |
    | -------------------------------- | ------ | ------------------------------- |
    | `contacts[].name.formatted_name` | string | Full name of the shared contact |
    | `contacts[].phones[].phone`      | string | Phone number                    |
    | `contacts[].emails[].email`      | string | Email address                   |
  </Accordion>

  <Accordion title="Interactive — Button Reply">
    Received when a user taps one of the quick-reply buttons you sent.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900400",
      "type": "interactive",
      "interactive": {
        "type": "button_reply",
        "button_reply": {
          "id": "home_delivery",
          "title": "Home Delivery"
        }
      }
    }
    ```

    | Field                            | Type   | Description                                            |
    | -------------------------------- | ------ | ------------------------------------------------------ |
    | `interactive.button_reply.id`    | string | The `reply.id` you set when sending the button message |
    | `interactive.button_reply.title` | string | The button label shown to the user                     |
  </Accordion>

  <Accordion title="Interactive — List Reply">
    Received when a user selects a row from the list message you sent.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900450",
      "type": "interactive",
      "interactive": {
        "type": "list_reply",
        "list_reply": {
          "id": "track_order",
          "title": "Track Order",
          "description": "Find out where your order is"
        }
      }
    }
    ```

    | Field                    | Type   | Description                               |
    | ------------------------ | ------ | ----------------------------------------- |
    | `list_reply.id`          | string | The row `id` you set in the list sections |
    | `list_reply.title`       | string | The row title                             |
    | `list_reply.description` | string | The row description (if set)              |
  </Accordion>

  <Accordion title="Reaction Message">
    Received when a user reacts to one of your messages with an emoji.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900500",
      "type": "reaction",
      "reaction": {
        "message_id": "wamid.HBgNOTA1Mzk5ODc2NTQzFQIAERgSM0Y3RDg5NjREOUNBMkFFNEE3AA==",
        "emoji": "👍"
      }
    }
    ```

    | Field                 | Type   | Description                                           |
    | --------------------- | ------ | ----------------------------------------------------- |
    | `reaction.message_id` | string | The `wamid` of the message that was reacted to        |
    | `reaction.emoji`      | string | The emoji character (empty string = reaction removed) |
  </Accordion>

  <Accordion title="Order Message">
    Received when a user places an order through a WhatsApp catalog.

    ```json theme={null}
    {
      "from": "905399876543",
      "id": "wamid.xxx",
      "timestamp": "1711900550",
      "type": "order",
      "order": {
        "catalog_id": "CATALOG_ID_123",
        "text": "Please deliver before 6pm",
        "product_items": [
          {
            "product_retailer_id": "SKU-001",
            "quantity": 2,
            "item_price": 19.99,
            "currency": "USD"
          }
        ]
      }
    }
    ```

    | Field                                       | Type   | Description                   |
    | ------------------------------------------- | ------ | ----------------------------- |
    | `order.catalog_id`                          | string | Meta catalog ID               |
    | `order.text`                                | string | Note from the user (optional) |
    | `order.product_items[].product_retailer_id` | string | Your product SKU/ID           |
    | `order.product_items[].quantity`            | number | Ordered quantity              |
    | `order.product_items[].item_price`          | number | Unit price at time of order   |
    | `order.product_items[].currency`            | string | ISO 4217 currency code        |
  </Accordion>
</AccordionGroup>

***

## Parsing Incoming Messages

<CodeGroup>
  ```javascript Node.js theme={null}
  function processWebhook(body) {
    const changes = body?.entry?.[0]?.changes ?? [];

    for (const change of changes) {
      const value = change.value;
      const contact = value?.contacts?.[0];

      for (const msg of value?.messages ?? []) {
        const from = msg.from;
        const name = contact?.profile?.name ?? 'Unknown';

        switch (msg.type) {
          case 'text':
            console.log(`[TEXT] ${name} (${from}): ${msg.text.body}`);
            break;

          case 'image':
          case 'audio':
          case 'document':
          case 'video':
          case 'sticker':
            console.log(`[${msg.type.toUpperCase()}] ${name} sent media: ${msg[msg.type].id}`);
            // Download via Media API using msg[msg.type].id
            break;

          case 'location':
            console.log(`[LOCATION] ${name}: ${msg.location.latitude}, ${msg.location.longitude}`);
            break;

          case 'interactive':
            if (msg.interactive.type === 'button_reply') {
              console.log(`[BUTTON] ${name} tapped: ${msg.interactive.button_reply.id}`);
            } else if (msg.interactive.type === 'list_reply') {
              console.log(`[LIST] ${name} selected: ${msg.interactive.list_reply.id}`);
            }
            break;

          case 'reaction':
            console.log(`[REACTION] ${name} reacted ${msg.reaction.emoji} to ${msg.reaction.message_id}`);
            break;

          default:
            console.log(`[UNHANDLED] type: ${msg.type}`);
        }
      }
    }
  }
  ```

  ```python Python theme={null}
  def process_webhook(body):
      changes = body.get("entry", [{}])[0].get("changes", [])

      for change in changes:
          value = change.get("value", {})
          contact = (value.get("contacts") or [{}])[0]
          name = contact.get("profile", {}).get("name", "Unknown")

          for msg in value.get("messages", []):
              from_num = msg["from"]
              msg_type = msg["type"]

              if msg_type == "text":
                  print(f"[TEXT] {name} ({from_num}): {msg['text']['body']}")

              elif msg_type in ("image", "audio", "document", "video", "sticker"):
                  media_id = msg[msg_type]["id"]
                  print(f"[{msg_type.upper()}] {name} sent media: {media_id}")
                  # Download via Media API using media_id

              elif msg_type == "location":
                  loc = msg["location"]
                  print(f"[LOCATION] {name}: {loc['latitude']}, {loc['longitude']}")

              elif msg_type == "interactive":
                  if msg["interactive"]["type"] == "button_reply":
                      btn_id = msg["interactive"]["button_reply"]["id"]
                      print(f"[BUTTON] {name} tapped: {btn_id}")
                  elif msg["interactive"]["type"] == "list_reply":
                      row_id = msg["interactive"]["list_reply"]["id"]
                      print(f"[LIST] {name} selected: {row_id}")

              elif msg_type == "reaction":
                  emoji = msg["reaction"]["emoji"]
                  msg_id = msg["reaction"]["message_id"]
                  print(f"[REACTION] {name} reacted {emoji} to {msg_id}")

              else:
                  print(f"[UNHANDLED] type: {msg_type}")
  ```
</CodeGroup>

***

## Tips

<Tip>
  Always handle the `default` / `else` case for unknown `type` values. Meta regularly introduces new message types (polls, payment events, etc.) and unhandled types will otherwise cause silent failures in your pipeline.
</Tip>

<Note>
  For media messages, `image.id`, `audio.id`, etc. are temporary Media IDs that expire after **30 days**. Download and store the file on your own infrastructure promptly.
</Note>

<Warning>
  The same incoming message may be delivered more than once due to network retries. Use `messages[0].id` (the `wamid`) as an idempotency key in your database before processing.
</Warning>
