# Retrieve a message

> Read one message, on any channel, with its current status, cost, failure details, and the content the recipient received.

`GET https://api-connect.nxiom.com/api/v1/messaging/messages/{messageId}`

## Authorization

Requires `whatsapp.send` to read WhatsApp messages. A key with `whatsapp.full_access` can also read them. WhatsApp must be turned on for your organization.

## Path parameters

| Field | Type | Description |
| --- | --- | --- |
| `messageId` | string · required | The message ID returned by [Send a message](/docs/api/messaging/send), starting with `msg_`. |

## Request

### cURL

```shell
curl "https://api-connect.nxiom.com/api/v1/messaging/messages/msg_example" \
  -H "Authorization: Bearer $NEXIOM_API_KEY"
```

### Node.js

```typescript
import { NexiomConnect } from '@nexiom/connect';

const apiKey = process.env.NEXIOM_API_KEY;
if (!apiKey) throw new Error('Set NEXIOM_API_KEY');

const nexiom = new NexiomConnect({ apiKey });

const { data, error } = await nexiom.messaging.get('msg_example');

if (error) throw new Error(`${error.code}: ${error.message}`);
console.log(data.status, data.content?.body?.map((segment) => segment.text).join(''));
```

### PHP

```php
<?php

use Nexiom\Connect\NexiomConnect;

$apiKey = getenv('NEXIOM_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('Set NEXIOM_API_KEY');
}

$nexiom = new NexiomConnect($apiKey);

$message = $nexiom->messaging->get('msg_example');

echo $message['status'];
```

## Response

HTTP `200`. Example identifiers below are illustrative.

`data` is the [message object](#the-message-object), with the `content` the recipient received. Messages are kept for 30 days; after that this endpoint returns `404`.

### 200 OK

The message was delivered and read.

```json
{
  "message": "Message fetched",
  "data": {
    "id": "msg_example",
    "channel": "whatsapp",
    "status": "read",
    "sender": "+213555000111",
    "sender_name": "Acme",
    "recipient": "+213555123456",
    "category": "utility",
    "template": {
      "id": "wat_example",
      "name": "order_update",
      "language": "en_US",
      "version": 1
    },
    "is_billable": true,
    "cost": "0.0000",
    "cost_currency": "DZD",
    "failure_code": null,
    "failure_reason": null,
    "created_at": "2026-10-14T09:30:00.000Z",
    "accepted_at": "2026-10-14T09:30:01.000Z",
    "sent_at": "2026-10-14T09:30:02.000Z",
    "delivered_at": "2026-10-14T09:30:03.000Z",
    "read_at": "2026-10-14T09:41:27.000Z",
    "failed_at": null,
    "content": {
      "header": null,
      "body": [
        { "text": "Hi ", "variable": null },
        { "text": "Amina", "variable": "1" },
        { "text": ", your order ", "variable": null },
        { "text": "A-1234", "variable": "2" },
        { "text": " has shipped. You can track it from your account.", "variable": null }
      ],
      "footer": null,
      "buttons": []
    }
  }
}
```

### 401 Unauthorized

The API key is missing, malformed, revoked, or expired.

```json
{
  "error": "unauthorized",
  "message": "Invalid API key",
  "correlationId": "req_example"
}
```

### 403 Forbidden

The API key lacks whatsapp.send, or WhatsApp is not turned on for your organization (code: FEATURE_NOT_AVAILABLE).

```json
{
  "error": "not_allowed",
  "message": "Missing required API key permissions: whatsapp.send",
  "correlationId": "req_example"
}
```

### 404 Not Found

No message with this ID exists in the key's project, or it was deleted after 30 days.

```json
{
  "error": "not_found",
  "code": "message_not_found",
  "message": "Message not found.",
  "correlationId": "req_example"
}
```

## The message object

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Message ID, starting with `msg_`. |
| `channel` | string | `whatsapp`. The channel the message was sent on; it decides the channel-specific fields. |
| `status` | string | `sending`, `accepted`, `sent`, `delivered`, `read`, `failed`, or `uncertain`. See [Message statuses](/docs/whatsapp/sending#message-statuses). |
| `sender` | string | Phone number the message was sent from, in E.164 format. |
| `sender_name` | string or null | The number's display name approved by WhatsApp, when there is one. |
| `recipient` | string | Recipient phone number, in E.164 format. |
| `category` | string or null | `marketing`, `utility`, or `authentication`. The template's category when the message was sent. |
| `template` | object or null | The template sent: `id`, `name`, `language` (such as `en_US`), and `version`, which increases when the template's content or category changes. |
| `is_billable` | boolean | Whether the message counts toward your plan's included messages or is paid from your wallet beyond them. |
| `cost` | string | What Nexiom Connect charged for the message, as a decimal string such as `"0.1000"`. `"0.0000"` for included messages and messages not charged. Never includes Meta's fees. |
| `cost_currency` | string | ISO 4217 currency of `cost`, such as `DZD`. |
| `failure_code` | string or null | For a failed message: `meta_` followed by WhatsApp's error code, such as `meta_131026`, or `meta_error`. See [failure codes](/docs/whatsapp/best-practices#whatsapp-failure-codes). |
| `failure_reason` | string or null | For a failed message: WhatsApp's explanation. |
| `created_at` | string | When the message was created. |
| `accepted_at` | string or null | When WhatsApp accepted the message. |
| `sent_at` | string or null | When WhatsApp sent it to the recipient's phone. |
| `delivered_at` | string or null | When it reached the recipient's phone. `null` if WhatsApp skipped straight to `read`. |
| `read_at` | string or null | When the recipient opened it. Only for recipients who share read receipts. |
| `failed_at` | string or null | When the message failed. |
| `content` | object or null | The message as the recipient received it. |
| `content.header` | array or null | The header as text segments, or `null` when the template has no text header. |
| `content.body` | array or null | The body as text segments. |
| `content.footer` | string or null | The footer text. |
| `content.buttons` | string[] | The button labels, in order. |

Timestamps are ISO 8601 strings in UTC. Each segment of `content.header` and `content.body` is either template text, with `variable` set to `null`, or a variable, with `variable` set to its key and `text` set to the value sent:

```json
[
  { "text": "Hi ", "variable": null },
  { "text": "Amina", "variable": "1" }
]
```

Join the segments' `text` to get the full text. Meta's own message ID and your API credentials are never returned.

---

Source: https://connect.nxiom.com/docs/api/messaging/retrieve
