---
title: "List messages"
method: GET
path: "/v1/messaging/inbox/conversations/{conversationId}/messages"
tags: ["Messages"]
---

# List messages

`GET /v1/messaging/inbox/conversations/{conversationId}/messages`

## Request

- Base URL: `https://apihub.co.il`
- URL: `https://apihub.co.il/v1/messaging/inbox/conversations/{conversationId}/messages`
- Auth: HTTP bearer

Fetch messages for a specific conversation, with cursor-based pagination
and ordering control.

Pagination: pass `pagination.nextCursor` from a prior response back as
the `cursor` query param to fetch the next page. The cursor is opaque;
do not parse or construct it client-side.

Sort order: defaults to `asc` (oldest first, chat style). For the
"show me the latest messages" pattern, pass `?sortOrder=desc&limit=N`.
X, Instagram, Telegram, WhatsApp and Reddit honor the requested
order from the local message store. For Facebook and Bluesky, the
upstream APIs only return newest-first and have no order parameter, so
sort order is best-effort and only reverses items within a single page
(pages still walk newest→oldest). The response field `sortOrderApplied`
tells you what was actually applied.

Reddit threads are paginated client-side because Reddit's API has no
per-thread cursor. Very long threads may be upstream-truncated by
Reddit's inbox/sent windows (~100 most-recent items each); this is a
Reddit platform limitation.

Instagram and Facebook conversations include history from before the
account was connected, replayed from Meta. That replay covers the 500
most recent messages per conversation: a longer thread keeps its newest
500 and older messages are not retrievable. Messages that arrived after
the account was connected are unaffected. Replayed messages are stored
as already read and emit no webhooks.

X limitation: X's encrypted "X Chat" messages are not accessible via the API. Conversations where the other participant uses encrypted X Chat may only show your outgoing messages. See the list conversations endpoint for more details.

This endpoint is read-only and does NOT mark messages as read or send
read receipts. To mark a conversation read (and send WhatsApp blue ticks
on eligible accounts), call `POST /v1/inbox/conversations/{conversationId}/read`.


**Billing:** Read (free unless it says otherwise) · **Rate limit:** 120/min

## Path parameters

- `conversationId` string, required: Opaque conversation identifier, accepted verbatim from the list endpoint or from the conversationId on inbox webhooks. Format not to be assumed.

## Query parameters

- `limit` integer: Number of messages to return per page. Default 100, max 100.
- `cursor` string: Opaque pagination cursor. Pass `pagination.nextCursor` from a prior response verbatim: a cursor we cannot parse returns 400 rather than silently restarting from the first page.
- `accountId` string, required: Account ID
- `sortOrder` 'asc' | 'desc': Order of returned messages. Default `asc` (oldest first, chat style). X, Instagram, Telegram, WhatsApp and Reddit honor this order across cursor pages. For Facebook and Bluesky, only intra-page ordering is affected. Pages always walk newest→oldest. See `sortOrderApplied` in the response.

## Headers

- `Idempotency-Key` string
- `X-Tag` string

## Response `200`

Completed

- object
  - `id` string: Execution id — stable across internal retries; use it with GET /v1/executions/{id}
  - `status` 'pending' | 'processing' | 'completed' | 'partial' | 'failed' | 'cancelled' | 'timeout'
  - `operation` string
  - `tag` string, nullable: Your X-Tag, if sent
  - `created_at` string, date-time
  - `completed_at` string, date-time, nullable
  - `output` object: Operation result (see each operation). While a Studio render is processing: `stage` (queued · transcribing · downloading · preparing · cleaning_voice · mixing_audio · rendering · finishing), `phase` (the engine's: download · prepare · voice · audio · encode · qa · upload, or null), `progress` (a percent, 0–100) and `progress_fraction` (0–1), `eta_seconds` (seconds left, never below 0) and `estimate_seconds`
    - `status` string
    - `messages` object[]
      - `id` string: The platform's own message id: the `wamid` on WhatsApp, the `mid` on Instagram and Facebook Messenger. This is what `metadata.quotedMessageId` points at, the value to pass as `replyTo` on the platforms that support quote-replies, and the `{messageId}` segment of the attachment-resolve URL. Webhooks deliver the same value as `message.platformMessageId`; this response has no field by that name.
      - `readAt` string, date-time, nullable
      - `sentAt` string, date-time, nullable: Original send time for outgoing messages (used for Messenger watermark queries).
      - `message` string
      - `sentVia` 'human' | 'api' | 'broadcast' | 'sequence' | 'workflow' | 'comment_automation' | 'bulk-api' | 'null', nullable: Which Zernio surface produced this outgoing message: `human` (an operator in the Zernio inbox), `api` (a call to this API), `broadcast`, `sequence`, `workflow`, `comment_automation`, or `bulk-api` (POST /v1/whatsapp/bulk). Same vocabulary as the `source` filter on the inbox analytics endpoints. Always present, and `null` whenever the lineage is unknown: every incoming message, any outgoing message sent from the platform's own app, and every message stored before this field shipped (2026-08). Existing messages are NOT backfilled, so treat `null` as "unknown", never as "sent by a human".
      - `subject` string, nullable: Reddit message subject
      - `editedAt` string, date-time, nullable: When the most recent edit happened.
      - `isEdited` boolean: True if the sender has edited this message at least once.
      - `metadata` object: Platform-specific extras. Free-form, but commonly includes: `quotedMessageId` (the `id` of the message this one replies to, delivered as `message.platformMessageId` on webhooks), `waInteractive` (a compact descriptor of WhatsApp interactive content sent: buttons / list / cta_url / flow / location_request), `metaInteractive` (outgoing Instagram/Facebook buttons, quickReplies and template, as sent), and for inbound interactive taps `interactiveType` / `interactiveId`. It can also carry `source` (`whatsapp_business_app` / `coexistence_history` on a WhatsApp Coexistence number, `bulk-api` on a POST /v1/whatsapp/bulk send), which is where the message reached us from rather than who produced it: read `sentVia` for that.
      - `platform` string
      - `senderId` string
      - `accountId` string
      - `createdAt` string, date-time
      - `deletedAt` string, date-time, nullable
      - `direction` 'incoming' | 'outgoing'
      - `editCount` integer: Total number of edits applied.
      - `isDeleted` boolean: True if the sender has deleted (unsent) this message. The original message and attachments fields remain populated.
      - `reactions` object[]: Emoji reactions on this message (WhatsApp / Telegram). At most one per party in a 1:1 thread.
        - `emoji` string
        - `fromMe` boolean: true if the connected account reacted, false if the contact did.
        - `reactedAt` string, date-time
      - `senderName` string, nullable
      - `storyReply` object: Instagram only. Present when the message replies to one of the account's stories. Also set on history imported after connecting, read off Meta's `story.reply_to`.
        - `storyId` string: The Instagram story ID the user replied to.
        - `storyUrl` string: Meta CDN URL for the story media. Expires roughly 24 hours after the story posted; fetch promptly or treat 404s as expected.
      - `attachments` object[]
        - `id` string
        - `url` string: Direct media link. On Instagram and Facebook this is a signed Meta CDN url that EXPIRES: use it now, do not store it. Persist `refreshUrl` instead.
        - `type` 'image' | 'video' | 'audio' | 'file' | 'sticker' | 'share' | 'template' | 'unsupported_type': On Instagram and Facebook a shared reel, post or ad reaches Zernio with no type of its own (Meta's `unsupported_type`) and is resolved from the media's Content-Type at ingest into `image`, `video`, `audio` or `file` with `originalType: "unsupported_type"`. `unsupported_type` is returned only when the CDN could not be classified in time.
        - `payload` object: Template content (title, subtitle, image, buttons) when type is template
        - `filename` string, nullable
        - `mimeType` string: MIME type of the media when Zernio knows it. On Instagram and Facebook it is set for shares resolved by content type (`originalType: "unsupported_type"`).
        - `previewUrl` string, nullable
        - `refreshUrl` string, nullable: Instagram and Facebook only. Endpoint that resolves this attachment to a working url every time, re-minting it from Meta when the stored one has expired. Safe to store and render indefinitely, except for an attachment with `originalType: "unsupported_type"`: Meta cannot re-serve those, so the endpoint answers 404 once the url has expired.
        - `originalType` string: Instagram and Facebook only, and present only when it differs from `type`. Meta's own type before normalization: `ig_reel` and `reel` become `video`, while `ig_post`, `post`, `ig_story` and `story_mention` become `share`. A story mention is `type: "share"` with `originalType: "story_mention"`; render on this field, since `share` alone is ambiguous. `originalType: "unsupported_type"` marks a share Meta did not classify, resolved by content type: `refreshUrl` cannot re-mint it (Meta answers `is_unsupported` with no attachments for the message node), so download it when the `message.received` webhook arrives.
      - `deliveredAt` string, date-time, nullable
      - `editHistory` object[]: Every prior version of the message, oldest first.
        - `text` string, nullable, required
        - `editedAt` string, date-time, required
        - `attachments` object[], required
          - `url` string
          - `type` string
          - `payload` object
      - `deliveryError` object, nullable: Populated when deliveryStatus === "failed".
        - `code` integer
        - `href` string, uri: Link to the platform's documentation for `code`, when the platform sent one.
        - `title` string
        - `details` string: Platform's extended detail for `code` (WhatsApp: Meta's `error_data.details`), when the platform sent one. Absent on SMS.
        - `message` string
      - `conversationId` string
      - `deliveryStatus` 'sent' | 'delivered' | 'read' | 'played' | 'failed' | 'deleted', nullable: Lifecycle status for outgoing messages. Not all platforms emit every state (see webhook support matrix).
      - `isStoryMention` boolean: Instagram only. True when the message is the user mentioning the account in their own story. The story itself is the `share` attachment with `originalType: "story_mention"`. Also set on imported history, read off Meta's `story.mention`.
      - `senderVerifiedType` 'blue' | 'government' | 'business' | 'none', nullable: X verified badge type. Only present for X messages.
      - `noRenderableContent` boolean: Instagram and Facebook Messenger only. True when Meta withholds the content of this message from the API (its `is_unsupported` flag): `message` is empty, `attachments` is empty, and there is nothing to fetch, now or later. Distinguishes such a message from an ordinary empty one such as a story reply with no text. Absent on other platforms.
    - `pagination` object
      - `hasMore` boolean: Whether more messages are available beyond this page.
      - `nextCursor` string, nullable: Opaque cursor to fetch the next page. `null` on the last page.
    - `lastUpdated` string, date-time
    - `sortOrderApplied` 'asc' | 'desc': Sort order actually applied to the returned page. May differ from the requested `sortOrder` for Facebook and Bluesky (always `desc` regardless of request).
  - `error` string, nullable
  - `usage` object
    - `credits_charged` number, nullable
    - `credits_reserved` number
    - `estimated_credits` number
    - `cost_source` 'provider_reported' | 'calculated' | 'estimated' | 'null', nullable
    - `provider_usage` object, nullable: Normalised consumption, e.g. { VIDEO_SECOND: 22.4 }
  - `balance` object
    - `available` number
    - `reserved` number

## Other responses

- `400`: Invalid input
- `402`: Insufficient credits / project budget
- `404`: Resource not found (or not yours)
- `429`: Rate limited
- `503`: Service temporarily paused

---

[API](https://skmtc.dev/apihub/apis/apihub-one-api-for-chat-image-video-ai.md) · [All operations](https://skmtc.dev/apihub/apis/apihub-one-api-for-chat-image-video-ai/llms.txt) · [OpenAPI document](https://skmtc.dev/apihub/apis/apihub-one-api-for-chat-image-video-ai/revisions/a8caa42835ce?raw)
