---
title: Message types | API Docs
description: Every part type you can send on WhatsApp, with a minimal example and its limits, and the types you receive.
---

A message’s content is its `parts` array, and each part’s `type` decides what the customer sees. Send one part per request, with either `POST /v1/messages` or the chat route `POST /v1/chats/{chat}/messages`. A request with two parts is refused with `error.code` [1019](/channel/whatsapp/error/codes/1xxx/1019/index.md).

| `type`                                          | Customer sees        | In window | Outside window |
| ----------------------------------------------- | -------------------- | --------- | -------------- |
| [`text`](#text)                                 | Text                 | Yes       | No             |
| [`media`](#media)                               | Image, video, file   | Yes       | No             |
| [`location`](#location)                         | Map pin              | Yes       | No             |
| [`contacts`](#contacts)                         | Contact cards        | Yes       | No             |
| [`reaction`](#reaction)                         | Emoji on a message   | Yes       | No             |
| [`interactive_buttons`](#interactive_buttons)   | Reply buttons        | Yes       | No             |
| [`interactive_list`](#interactive_list)         | Pick-list menu       | Yes       | No             |
| [`interactive_cta_url`](#interactive_cta_url)   | Link button          | Yes       | No             |
| [`interactive_carousel`](#interactive_carousel) | Scrolling cards      | Yes       | No             |
| [`location_request`](#location_request)         | Send-location button | Yes       | No             |
| [`contact_request`](#contact_request)           | Share-contact button | Yes       | No             |
| [`template`](#template)                         | Approved template    | Yes       | Yes            |

The window is the 24-hour customer window. Outside it only an approved `template` sends; anything else is refused with `error.code` [2036](/channel/whatsapp/error/codes/2xxx/2036/index.md). See [Sending messages](/channel/whatsapp/guides/messaging/sending-messages#choose-content-from-the-customer-window/index.md) for the window, idempotency and outcomes.

Group chats accept only `text`, standard `media` (not voice notes) and approved text or media `template` parts.

The exact schema for each part is served at `GET /v1/parts/{type}`. Content that breaks a limit is rejected with a JSON Pointer to the field, never truncated or converted.

Examples below show the request body for the chat route,

`POST /v1/chats/{chat}/messages`. With `POST /v1/messages`, add the customer’s address as `to`.

## text

Plain text. URLs render as tappable links.

```
{ "parts": [{ "type": "text", "body": "Your order is on its way." }] }
```

- `body`: required, up to 4,096 characters, not blank.
- `preview_url`: `true` shows a preview card for the first URL. Default `false`.

## media

One image, video, audio file, document or sticker. Name the bytes with exactly one of `upload_ref` (from `POST /v1/media`) or `source_url` (a public `https` address fetched once, before the send is accepted). [Attachments](/channel/whatsapp/guides/messaging/attachments/index.md) covers both routes.

```
{
  "parts": [
    {
      "type": "media",
      "kind": "image",
      "upload_ref": "upload.example",
      "caption": "Today's menu"
    }
  ]
}
```

- `kind`: `image`, `video`, `audio`, `document` or `sticker`.
- `caption`: up to 1,024 characters; `image`, `video` and `document` only.
- `filename`: up to 240 characters; `document` only.
- `source_url`: up to 2,048 characters.

| `kind`     | Upload limit (bytes)              | Media types                              |
| ---------- | --------------------------------- | ---------------------------------------- |
| `image`    | 5,000,000                         | JPEG, PNG                                |
| `video`    | 16,000,000                        | MP4, 3GPP                                |
| `audio`    | 16,000,000                        | AAC, AMR, MPEG, MP4, Ogg                 |
| `document` | 100,000,000                       | Plain text, PDF, Word, Excel, PowerPoint |
| `sticker`  | 100,000 static / 500,000 animated | WebP                                     |

### Voice notes

An `audio` part with `"voice": true` arrives as a voice note instead of an audio file.

```
{
  "parts": [
    {
      "type": "media",
      "kind": "audio",
      "upload_ref": "upload.example",
      "voice": true
    }
  ]
}
```

- The upload must be `audio/ogg` holding mono Opus audio. Bytes are never converted.
- 512 KB or smaller shows a play button; larger is delivered but must be downloaded first.
- Individual chats only.

## location

A map pin.

```
{
  "parts": [
    {
      "type": "location",
      "latitude": 37.7749,
      "longitude": -122.4194,
      "name": "Downtown store",
      "address": "100 Main St, San Francisco, CA"
    }
  ]
}
```

- `latitude` (−90 to 90) and `longitude` (−180 to 180): required, never defaulted.
- `name`, `address`: optional, up to 1,000 characters each.

## contacts

One or more contact cards.

```
{
  "parts": [
    {
      "type": "contacts",
      "contacts": [
        {
          "name": { "formatted_name": "Ana Ruiz" },
          "phones": [{ "phone": "+15550101234", "kind": "CELL" }]
        }
      ]
    }
  ]
}
```

- 1 to 5 cards.
- `name.formatted_name`: required, up to 512 characters, not blank.
- Optional `phones`, `emails`, `urls`, `addresses`, `org`, `birthday` (`YYYY-MM-DD`).
- `origin` is response-only and appears on inbound cards; a send carrying it is refused. See [`contact_request`](#contact_request).

## reaction

An emoji on an earlier message in the chat.

```
{
  "parts": [{ "type": "reaction", "message_id": "msg_example", "emoji": "👍" }]
}
```

- `message_id`: the API’s own message id, not `channel_message_id`.
- `emoji`: required; an empty string removes your earlier reaction.
- Ends at `sent`: no delivered or read receipt. See [React to a message](/channel/whatsapp/guides/messaging/sending-messages#react-to-a-message/index.md).

## interactive\_buttons

Body text with up to three reply buttons. A tap arrives as an [`interactive_reply`](#messages-you-receive) with `kind: "button_reply"` and the button’s `id`.

```
{
  "parts": [
    {
      "type": "interactive_buttons",
      "body": "Did your order arrive?",
      "buttons": [
        { "id": "arrived-yes", "title": "Yes" },
        { "id": "arrived-no", "title": "No" }
      ]
    }
  ]
}
```

- `body`: up to 1,024 characters.
- `buttons`: 1 to 3. `title` up to 20 characters, `id` up to 256; both unique.
- `header` (text, up to 60) or `media_header` (`image`, `video` or `document` by `upload_ref`), not both.
- `footer`: up to 60 characters.

## interactive\_list

Body text with a button that opens a sectioned list. A pick arrives as an [`interactive_reply`](#messages-you-receive) with `kind: "list_reply"` and the row’s `id`.

```
{
  "parts": [
    {
      "type": "interactive_list",
      "body": "Choose a delivery slot.",
      "button": "See slots",
      "sections": [
        {
          "rows": [
            {
              "id": "slot-am",
              "title": "Morning",
              "description": "8am to 12pm"
            },
            {
              "id": "slot-pm",
              "title": "Afternoon",
              "description": "12pm to 5pm"
            }
          ]
        }
      ]
    }
  ]
}
```

- `button`: up to 20 characters. `body`: up to 1,024.
- `sections`: 1 to 10; a section `title` (up to 24) is required once there are two or more.
- Up to 10 rows in total across all sections. Row `id` up to 200, unique across sections.
- Row `title` up to 24, `description` up to 72.
- `header`, `footer`: text only, up to 60 characters.

## interactive\_cta\_url

Body text with one button that opens a URL.

```
{
  "parts": [
    {
      "type": "interactive_cta_url",
      "body": "Track your parcel.",
      "display_text": "Track",
      "url": "https://example.com/track/A-1042"
    }
  ]
}
```

- `display_text`: up to 20 characters.
- `url`: absolute `http` or `https`, up to 2,000 characters.
- `header` (text, up to 60) or `media_header`, not both.
- `footer`: text only, up to 60 characters.

### Media header

`media_header` shows an uploaded image, video or document above the body. Upload the file with `POST /v1/media`, then name it with the matching `kind`:

```
{
  "parts": [
    {
      "type": "interactive_cta_url",
      "media_header": {
        "kind": "document",
        "upload_ref": "upload.example",
        "filename": "Menu.pdf"
      },
      "body": "This week's menu",
      "display_text": "Order now",
      "url": "https://example.com/order"
    }
  ]
}
```

- `kind`: `image`, `video` or `document`, matching the upload’s kind.
- `filename`: up to 240 characters; `document` only.
- `header` with `media_header`, or `filename` on an image or video header, is refused with `422 invalid_content` and a pointer at the member.
- A missing upload is refused with `422 upload_ref_not_found`; an upload of another kind with `422 upload_ref_invalid`.

## interactive\_carousel

A body above 2 to 10 cards that scroll sideways, each showing an image or a video. For image cards, upload each image with `POST /v1/media`, then list the cards in `card_index` order.

```
{
  "parts": [
    {
      "type": "interactive_carousel",
      "body": "Three new listings near you",
      "cards": [
        {
          "card_index": 0,
          "header": { "kind": "image", "upload_ref": "upload.example0" },
          "body": "2 bed, garden",
          "reply_buttons": [{ "id": "listing-0-like", "title": "Like" }]
        },
        {
          "card_index": 1,
          "header": { "kind": "image", "upload_ref": "upload.example1" },
          "body": "Loft, city view",
          "reply_buttons": [{ "id": "listing-1-like", "title": "Like" }]
        },
        {
          "card_index": 2,
          "header": { "kind": "image", "upload_ref": "upload.example2" },
          "body": "Studio, near park",
          "reply_buttons": [{ "id": "listing-2-like", "title": "Like" }]
        }
      ]
    }
  ]
}
```

- `body`: up to 1,024 characters.
- `cards`: 2 to 10. `card_index` starts at 0 and matches the card’s position.
- Card `header`: an `image` by `upload_ref`, or a `video` by `url` ([video cards](#video-cards)).
- Every card has the same header kind: all images or all videos.
- Card `body`: optional, up to 160 characters and two line breaks.
- Each card has one `url_button` (`display_text` up to 20, absolute `https` `url` up to 2,000) or 1 to 2 `reply_buttons`.
- Every card has the same kind of button, and the same number of reply buttons.
- Reply button `id`: up to 256, unique across the whole carousel. `title`: up to 20, unique within a card.

A reply-button tap arrives as a [`template_reply`](#messages-you-receive) whose `payload` is the button’s `id`. Nothing else names the card, so the `id` is the card’s identity. A URL-button tap sends you no event.

### Video cards

A video card names the public `https` address its video plays from, in `header.url`, instead of an upload:

```
{
  "parts": [
    {
      "type": "interactive_carousel",
      "body": "Take a tour before you visit",
      "cards": [
        {
          "card_index": 0,
          "header": {
            "kind": "video",
            "url": "https://cdn.example.com/tour-0.mp4"
          },
          "body": "Virtual tour",
          "url_button": {
            "display_text": "Book",
            "url": "https://example.com/book/0"
          }
        },
        {
          "card_index": 1,
          "header": {
            "kind": "video",
            "url": "https://cdn.example.com/tour-1.mp4"
          },
          "body": "Garden walk-through",
          "url_button": {
            "display_text": "Book",
            "url": "https://example.com/book/1"
          }
        }
      ]
    }
  ]
}
```

- An image card takes `upload_ref` and a video card takes `url`; the other way round is refused.
- `url`: up to 2,000 characters, absolute `https`, with its host named by a DNS name (no IP address, no percent-escapes in the host), no port (omit it), no credentials, no fragment, and no spaces or control characters. Anything else is refused with `422 invalid_content`, never rewritten.
- The video is never fetched before the send: the address is sent exactly as written, so it must be publicly reachable and serve a playable video.
- A link the customer’s WhatsApp cannot fetch is accepted, then reported as `message.failed` with the failure code `channel_refused`. See [Why a message failed](/channel/whatsapp/guides/messaging/sending-messages#why-a-message-failed/index.md).
- WhatsApp fetches each linked video before delivering, so a carousel with video cards can arrive after messages you send behind it. If order matters, wait for its `message.delivered` before sending the next message.

## location\_request

A prompt with a send-location button. The answer arrives as a `location` part.

```
{
  "parts": [
    {
      "type": "location_request",
      "body": "Share your location so we can find the nearest store."
    }
  ]
}
```

- `body`: required, up to 1,024 characters.

`address_request` also appears in the reference. It is reserved and cannot be sent yet.

## contact\_request

A prompt with a button that shares the customer’s own contact card with one tap. Useful when you know a customer only by a [username](/channel/whatsapp/guides/messaging/sending-messages#customers-who-use-a-username/index.md) and need a phone number.

```
{
  "parts": [
    {
      "type": "contact_request",
      "body": "Share your number so we can call you back."
    }
  ]
}
```

- `body`: required, up to 1,024 characters, not blank.
- Individual chats only; refused on a send to a group chat.

The shared card arrives as an ordinary inbound [`contacts`](#contacts) part. Each inbound card may carry `origin`:

| `origin`          | Meaning                                        |
| ----------------- | ---------------------------------------------- |
| `contact_request` | The customer tapped your share-contact button. |
| `other`           | The customer sent a card themselves.           |
| absent            | Not reported.                                  |

New values may appear; treat any other value as unrecognised. The shared card is not linked as a reply, so its message carries no `reply_to_message_id`: match it to your request by `origin` and timing.

```
{
  "parts": [
    {
      "type": "contacts",
      "contacts": [
        {
          "name": { "formatted_name": "Ana Ruiz" },
          "phones": [
            { "phone": "+15550101234", "messaging_id": "15550101234" }
          ],
          "origin": "contact_request"
        }
      ]
    }
  ]
}
```

## template

An approved template, and the one type that sends outside the window. Read each template’s `send_schema` from `GET /v1/templates` and fill its named `parameters`.

```
{
  "parts": [
    {
      "type": "template",
      "name": "order_shipped",
      "language": "en_US",
      "parameters": { "order_id": "A-1042" }
    }
  ]
}
```

- `name`: lowercase letters, digits and underscores, up to 512 characters.
- `language`: a code such as `en_US`, up to 32 characters.
- `header`, `buttons`, `cards`: only when the template’s `send_schema` asks for them.
- Authentication templates take one parameter, `code`, 1 to 15 characters.

See [Templates](/channel/whatsapp/guides/templates/index.md) to register one.

## Messages you receive

Inbound messages use the same `parts` array. These types arrive inbound; the last seven are never sendable.

| `type`              | What it is                                                                                                                                                                        |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`              | Text from the customer.                                                                                                                                                           |
| `media`             | A file. Carries `media_id` and a download `url`; see [Download incoming attachments](/channel/whatsapp/guides/messaging/sending-messages#download-incoming-attachments/index.md). |
| `location`          | A shared location, including an answer to `location_request`.                                                                                                                     |
| `contacts`          | Contact cards, including an answer to `contact_request`. Each card may carry `origin`; see [`contact_request`](#contact_request).                                                 |
| `reaction`          | An emoji on a message. Carries `channel_message_id`, and `message_id` when the chat holds the target.                                                                             |
| `interactive_reply` | A tap on `interactive_buttons` (`button_reply`) or `interactive_list` (`list_reply`). `id` is yours.                                                                              |
| `template_reply`    | A tap on a template quick-reply button or a carousel reply button. `payload` is the button’s value or `id`; `text` is its label.                                                  |
| `address_reply`     | A structured address the customer submitted.                                                                                                                                      |
| `order`             | An order placed from a product catalog.                                                                                                                                           |
| `referral`          | The ad or post a first message came from. Opens a longer window.                                                                                                                  |
| `system`            | A chat event, such as the customer changing number. `body` is readable.                                                                                                           |
| `unsupported`       | A message kind not yet typed. `raw` holds the original payload.                                                                                                                   |

For a template tap, the message’s `reply_to_message_id` names the template message that carried the button.
