# Get message by ID

> GET /v1/messages/{messageId}

`GET https://api.zavu.dev/v1/messages/{messageId}`

## Parameters

- `messageId` (path, string, required)

## Responses

### 200

Message details.

- `message` (object, required)
  - `id` (string, required)
  - `to` (string, required)
  - `from` (string)
  - `senderId` (string)
  - `channel` (string, required): Delivery channel. Use 'auto' for intelligent routing. One of: `auto`, `sms`, `sms_oneway`, `whatsapp`, `telegram`, `email`, `instagram`, `messenger`, `voice`.
  - `direction` (string, required): Who sent the message. Needed to render a thread: `status` cannot tell the two apart, because an inbound message is also stored as `delivered`. One of: `inbound`, `outbound`.
  - `messageType` (string, required): Type of message. Non-text types are supported by WhatsApp and Telegram (varies by type). `location_request` asks the recipient to share their location and is WhatsApp-only. It takes no `content` object — the prompt goes in `text` (max 1024 characters) and the button label is fixed by WhatsApp. The recipient's answer arrives as an inbound `location` message whose `content.replyToMessageId` is the ID of the request. `request_contact_info` asks the recipient to share their phone number and is WhatsApp-only. Like `location_request` it takes no `content` object — the prompt goes in `text` (max 1024 characters) and WhatsApp renders a fixed **Share Contact Info** button. The answer arrives as an inbound `contact` message. Use it to recover the phone number of a contact who adopted a WhatsApp username and is only known by their business-scoped user ID (BSUID); when they share it, Zavu automatically links the phone number to that contact. One of: `text`, `image`, `video`, `audio`, `document`, `sticker`, `location`, `contact`, `buttons`, `list`, `cta_url`, `request_contact_info`, `location_request`, `reaction`, `template`.
  - `status` (string, required) One of: `queued`, `sending`, `sent`, `delivered`, `read`, `failed`, `received`, `pending_url_verification`.
  - `text` (string): Text content or caption.
  - `content` (object): Content for non-text message types (WhatsApp and Telegram).
    - `mediaUrl` (string): URL of the media file (for image, video, audio, document, sticker).
    - `mediaId` (string): WhatsApp media ID if already uploaded.
    - `mimeType` (string): MIME type of the media.
    - `filename` (string): Filename for documents.
    - `latitude` (number): Latitude for location messages.
    - `longitude` (number): Longitude for location messages.
    - `locationName` (string): Name of the location.
    - `locationAddress` (string): Address of the location.
    - `contacts` (object[]): Contact cards for contact messages.
      - `name` (string)
      - `phones` (string[])
    - `buttons` (object[]): Interactive buttons (max 3).
      - `id` (string, required)
      - `title` (string, required)
    - `listButton` (string): Button text for list messages.
    - `sections` (object[]): Sections for list messages.
      - `title` (string, required)
      - `rows` (object[], required)
        - `id` (string, required)
        - `title` (string, required)
        - `description` (string)
    - `ctaDisplayText` (string): Button label for cta_url messages.
    - `ctaUrl` (string<uri>): Destination URL opened in the device's default browser when the button is tapped. Used with messageType=cta_url. WhatsApp requires HTTPS in production.
    - `ctaHeaderType` (string): Optional header type for cta_url messages. One of: `text`, `image`, `video`, `document`.
    - `ctaHeaderText` (string): Header text when ctaHeaderType is 'text'.
    - `ctaHeaderMediaUrl` (string<uri>): Public HTTPS URL of the header media when ctaHeaderType is 'image', 'video', or 'document'. WhatsApp fetches this URL — it must be publicly reachable and return the declared content type.
    - `footerText` (string): Optional footer text for cta_url messages.
    - `emoji` (string): Emoji for reaction messages.
    - `reactToMessageId` (string): Message ID to react to.
    - `replyToMessageId` (string): Zavu message ID of the quoted message this message replies to. **When sending:** set it to make the message a quoted reply to an earlier message in the same conversation, such as the `data.messageId` of a `message.inbound` webhook. Supported on WhatsApp (every message type except `reaction`) and Telegram. The quoted message must belong to this project (otherwise `404`), must have gone out on the same channel as this send, must belong to the conversation `to` addresses, must have been sent or received by the sender this message goes out from (pass it in `Zavu-Sender`), and must have a `providerMessageId`. A failed message and a Telegram button tap cannot be quoted. Any other case returns `400` instead of sending the message unquoted. The stored message then carries the rest of the `replyTo*` fields. **When receiving:** present on inbound messages that quote an earlier message. Omitted when the quoted message is not found in Zavu (e.g. an old or unknown message) — use replyToProviderMessageId in that case.
    - `replyToProviderMessageId` (string): Provider message ID (WhatsApp WAMID, or Telegram message ID) of the quoted message. Present whenever an inbound WhatsApp message is a reply, even if the quoted message is not stored in Zavu, and on outbound quoted replies. Read-only: to quote when sending, set replyToMessageId.
    - `replyToFrom` (string): Sender of the quoted message (phone number in E.164 format, or the Telegram chat ID). Read-only.
    - `replyToText` (string): Truncated snippet (up to 200 characters) of the quoted message's text, for display. Empty when the quoted message has no text (e.g. media). Read-only.
    - `replyToMessageType` (string): Type of the quoted message (text, image, video, etc.). Read-only.
    - `templateId` (string): Template ID for template messages.
    - `templateVariables` (object): Variables for body placeholders. Key them to match the template body: by position (`1`, `2`, ...) for positional templates, or by name (e.g. `customer_name`) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Named keys also resolve a named text-header variable. Do not mix positional and named keys in the same request. On WhatsApp, a value may not contain line breaks, tabs or more than 4 consecutive spaces: Meta refuses those at delivery, so the send is rejected with `400 invalid_request` instead (`details.field` names the value).
      - `{key}` (string)
    - `templateButtonVariables` (object): Variables for dynamic button placeholders (URL buttons and OTP buttons). Keys are the button index (0, 1, 2) in the template's `buttons` array — not the placeholder name. Values substitute the `{{1}}` placeholder inside that button's URL. **WhatsApp constraints:** - URL buttons only accept `{{1}}` — positional, numeric, no whitespace, no name. Named placeholders like `{{token}}` are stored as literal URL text by Meta and cannot be substituted. - At most one placeholder per URL button. - A template may have at most three buttons. - Static URL buttons (no placeholder) and `quick_reply` buttons are not included here.
      - `{key}` (string)
    - `templateHeaderVariables` (object): Value for a text-header variable, keyed by `1` (WhatsApp text headers allow at most one variable). Optional override. If omitted, Zavu resolves the header from `templateVariables` using the header placeholder's name (e.g. `novios`). Static text headers need no value. The same WhatsApp rule as `templateVariables` applies: no line breaks, tabs or more than 4 consecutive spaces.
      - `{key}` (string)
    - `templateHeaderMediaUrl` (string<uri>): HTTPS URL of the media for this send, for a WhatsApp template whose header is `image`, `video` or `document`. It replaces the file stored on the template for this message only; the template is not changed. WhatsApp fetches the URL when the message is sent, so it must be publicly reachable at that moment (a short-lived signed link works if it outlives the send). Without it, the template's stored header file is sent. A template whose header is `text`, or that has no header, is refused with `400 invalid_request` and `details.field` set to `content.templateHeaderMediaUrl`, before anything is sent or charged. A URL that is not HTTPS is refused with `400 invalid_request` and a `details.errors` entry whose `path` is `["content", "templateHeaderMediaUrl"]`. Ignored on channels other than WhatsApp.
    - `templateHeaderFilename` (string): File name WhatsApp shows the recipient for a `document` header, e.g. `invoice-1042.pdf`. Works with `templateHeaderMediaUrl`, or on its own to name the template's stored file. Only valid when the template's header is `document`: any other header is refused with `400 invalid_request` and `details.field` set to `content.templateHeaderFilename`, before anything is sent or charged. Ignored on channels other than WhatsApp.
    - `referral` (object): Click-to-WhatsApp (CTWA) ad attribution: where an inbound conversation came from. WhatsApp only. Present on the **first inbound message** of a conversation opened from a Meta ad or post, and on no message after it — so store it when it arrives rather than expecting it again. Organic conversations never carry it. Field names are camelCased to match the rest of this API; Meta sends them as snake_case (`ctwa_clid`, `source_id`, ...). Fields that do not apply are omitted: a `post` source has no click id, and an image ad has no `videoUrl`.
      - `sourceType` (string): Where the click came from. One of: `ad`, `post`.
      - `sourceId` (string): Identifier of the ad or post that produced the click.
      - `sourceUrl` (string<uri>): Meta permalink to the ad or post.
      - `headline` (string): Headline of the ad or post.
      - `body` (string): Body copy of the ad or post.
      - `mediaType` (string): Type of media on the ad, when it had any. One of: `image`, `video`.
      - `imageUrl` (string<uri>): Image of the ad. Present when `mediaType` is `image`.
      - `videoUrl` (string<uri>): Video of the ad. Present when `mediaType` is `video`.
      - `thumbnailUrl` (string<uri>): Thumbnail of the ad media.
      - `ctwaClid` (string): Click-to-WhatsApp click identifier. This is the value Meta's Conversions API needs to credit a conversion back to the ad that produced the conversation. Present on `ad` sources; a `post` source has none.
  - `conversationId` (string): ID of the conversation (inbox thread) this message belongs to. Use it to build a direct dashboard link: `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`. Omitted only on legacy messages created before conversation threading.
  - `providerMessageId` (string): Message ID from the delivery provider.
  - `errorCode` (string, nullable)
  - `errorMessage` (string, nullable)
  - `cost` (number, nullable): Zavu platform charge in USD for this message. Messaging is billed against your plan's monthly limits plus usage-based overage.
  - `costProvider` (number, nullable): Carrier and delivery cost in USD.
  - `costTotal` (number, nullable): Total cost in USD (platform charge + delivery cost).
  - `metadata` (object)
    - `{key}` (string)
  - `createdAt` (string<date-time>, required)
  - `updatedAt` (string<date-time>)

### 401

Unauthorized.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 404

Message not found.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

## Example

```bash
curl -X GET "https://api.zavu.dev/v1/messages/message_abc123" \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY"
```

```typescript
import Zavudev from "@zavudev/sdk";

const zavu = new Zavudev({ apiKey: process.env.ZAVUDEV_API_KEY });

const result = await zavu.messages.retrieve("message_abc123");

console.log(result);
```
