# Get WhatsApp Message Status

> Look up the delivery status of a previously-sent WhatsApp message via GET /v1/whatsapp/messages/{id} — status taxonomy, Meta wamid, polling guidance.

Returns the current status of a message you previously sent through the public API. Use this to track delivery progression — `queued` → `sent` → `delivered` → `read` (or `failed`).

## Which endpoint do I call?

`GET` to `/v1/whatsapp/messages/{id}` over HTTPS, where `id` is the message id returned from a previous [Send Message](./send-message) or [Send Template](./send-template) call. It needs the `whatsapp:send` scope, the same as the sends, and every key holds it today. A key limited to some agents can read only the messages sent through those agents.

```
GET /v1/whatsapp/messages/{id}
```

## What does the request look like?

```bash
curl https://api.mojeeb.app/v1/whatsapp/messages/01c45011-d803-4eb0-a762-3228a4c392f3 \
  -H "Authorization: Bearer mk_live_YOUR_KEY_HERE"
```

## What does a success response look like?

`HTTP 200 OK` with the message object: its current `status`, the original send's details, and, once delivery fails, why. Every field, with an example, is in the [reference for this endpoint](../api-reference/get-whats-app-message-status), rendered from the API's own contract so it is never out of date.

## What do the status values mean?

| `status` | Meaning |
|---|---|
| `queued` | Accepted by Mojeeb; not yet handed to Meta |
| `sent` | Meta acknowledged receipt — `platform_message_id` is now populated |
| `delivered` | Meta confirmed delivery to the customer's device |
| `read` | Customer opened the message (only if read receipts are enabled on their side) |
| `failed` | Send failed at some stage — `failure_reason` (stable) says why, with `failure_code`, `failure_detail` and `failure_href` from Meta when Meta reported them (a free-form text Meta refused at send time currently reads `Unknown` with no code), and `failed_at` the time |

Once `delivered` or `read`, a message never goes back to `sent`. `failed` is the exception: Mojeeb retries a failed send a few times, so `failed` can still turn into `sent` shortly afterwards. See [Is `failed` final?](#is-failed-final)

## What is `platform_message_id`?

Meta's `wamid` for the message. It's `null` while the status is `queued`; populated once the status reaches `sent`, and kept through `delivered` and `read`. A message that failed before Meta accepted it has none. Use it for cross-referencing in Meta's WhatsApp Business Manager logs if you ever need to trace a delivery issue with Meta support.

## How often should I poll?

For most workflows, polling every 5–10 seconds for the first minute is enough — most messages reach `sent` within seconds. After that, slow down: poll every 30 seconds for delivery confirmation, or stop polling entirely if you don't need it.

Status lookups count against your [rate limit](../rate-limits) (60/min/key by default), so don't hammer the endpoint. If you need real-time updates for many messages, contact support — we may add webhook delivery callbacks in a future release.

## What does a not-found response look like?

`HTTP 404 Not Found` with the standard envelope:

```json
{
  "error": {
    "type":           "not_found_error",
    "code":           "message_not_found",
    "message":        "No message found with the supplied id.",
    "correlation_id": "req_01KQ..."
  }
}
```

You'll see this if:
- The id doesn't exist
- The id belongs to a different organization
- The message was sent through an agent your key can't act on, when the key is limited to some agents

The last two answer 404 rather than 403 on purpose, so a key can't learn that a message it may not read exists.

An id that isn't a valid UUID doesn't reach this endpoint: it returns `404 endpoint_not_found`.

## Common questions

### Does the status response include the recipient and the message type?

Yes. `to` echoes the recipient in E.164 format and `type` is `text` or `template`, exactly as the send response reported them, so you can match a status to the message you sent without keeping your own lookup. Before October 11, 2026 the status response returned `to` as an empty string; that gap is closed.

### When are `sent_at` and `failed_at` set?

`sent_at` has a value only while `status` is `sent`: it is `null` while `queued`, and again once the message is `delivered`, `read` or `failed`, so don't keep it as a permanent hand-off time. `failed_at` has a value whenever `status` is `failed`. Branch on `status`, not on which timestamp is null.

### Is `failed` final?

Not at once. When the send to Meta fails, Mojeeb retries it up to three more times, a few seconds apart, and each try can take longer when Meta is slow. Treat `failed` as final once it has stayed `failed` for a couple of minutes.

### Can I look up a message I sent through the dashboard, not the API?

Currently, the API only returns messages sent through the public API. Dashboard sends and webhook-handled messages aren't returned. This is intentional for v1 — surfacing every message would expose internal types we haven't committed to.

### Does this endpoint count against rate limits?

Yes. Status lookups spend your key's default budget, which every endpoint that takes a key shares except the WhatsApp template list, whose lower limit is counted apart. See [Rate Limits](../rate-limits) for details.

### Can I bulk-look-up many messages at once?

Not in v1. Each lookup is a separate request. Bulk lookup is reserved as an additive `POST /v1/whatsapp/messages/lookup` endpoint for a future release if customers need it.
