---
title: "List a conversation's messages"
method: GET
path: "/v1/support/conversations/{conversation}/messages"
tags: ["Support Inbox"]
---

# List a conversation's messages

`GET /v1/support/conversations/{conversation}/messages`

## Request

- Base URL: `https://api.subscriby.net`
- URL: `https://api.subscriby.net/v1/support/conversations/{conversation}/messages`
- Auth: HTTP bearer

The thread's messages **oldest first**, 50 per page. `internal: true` notes are withheld unless the token also carries `support-conversation:update`: reading a private remark about a member takes the same permission as writing one.

`direction` is `inbound` (from the member) or `outbound` (from your team). `author_kind` is `contact`, `creator` or `system`; `author_user_id` names the team member on an outbound reply and is `null` for inbound and system messages.

`source` is the surface the message came through: `connector_chat` for a member writing to the connector's installation, `dashboard`, `api` or `mcp` for a reply from your team, and `connector_relay_dm` or `connector_relay_group` for a reply your team typed on the platform itself (into the relay's ping, or inside the thread the relay opened in a group). Messages recorded before the connector SDK carry the same three meanings under the Telegram connector's older words, `telegram_bot`, `telegram_relay_dm` and `telegram_relay_group`.

`delivery_status` on an outbound message is `pending` → `sent`, or `failed` / `unreachable`. **`unreachable` means the member has blocked the bot**: the reply is stored but will never arrive, and retrying will not help. `failure_reason` carries the detail.

`body` is `null` for media sent without a caption. A captioned photo puts the caption in `body` and does not create a second message. A member editing an earlier message updates the stored message in place and stamps `edited_at`; no new message is created and no event fires. Inbound messages are rate-limited per member: excess messages are dropped silently rather than queued, so a flooding member produces no burst of events.

Each entry of `attachments` carries the file's `kind`, `mime`, `file_name`, `size`, `width`, `height`, `duration` and `url`.

> **File ids are never returned.** A platform file id plus the bot token is enough to download the file straight from the platform, so it is treated as a credential. `url` is populated only after the file has been fetched at least once; it is `null` until then.

## Path parameters

- `conversation` string, uuid, required

## Query parameters

- `page` integer
- `per_page` integer
- `limit` integer

## Response `200`

The page.

- object
  - `data` SupportMessageResource[], required: The items on this page.
    - `id` string, required: The message's id, the value `reply_to_message_id` quotes.
    - `conversation_id` string, required: The thread the message belongs to.
    - `project_id` string, required: The project the thread belongs to.
    - `direction` string, required: `inbound` (from the member) or `outbound` (from the team).
    - `author_kind` string, required: `contact` (the member), `creator` (a team member) or `system`.
    - `author_user_id` string, nullable, required: The team member who wrote an outbound reply; null for inbound and system messages.
    - `type` string, required: What the message carries: `text`, `photo`, `video`, `audio`, `voice`, `document`, `sticker`, `animation`, `location` or `contact`.
    - `source` string, required: The surface the message came through: `connector_chat` for a member writing to the connector's installation, `dashboard`, `api` or `mcp` for a reply from the team, `connector_relay_dm` or `connector_relay_group` for a reply the team typed on the platform itself, `ai_assistant` for a drafted reply. Messages recorded before the connector SDK carry the same meanings under the first connector's older words, its key followed by `_bot`, `_relay_dm` and `_relay_group`.
    - `delivery_status` string, required: On an outbound message, `pending` then `sent`, or `failed` / `unreachable`. **`unreachable` means the member has blocked the bot**: the reply is stored but will never arrive, and retrying will not help.
    - `body` string, nullable, required: The text, or the caption of a media message; null for media sent without a caption.
    - `internal` boolean, required: True for a private note the team wrote for itself, never delivered to the member. Withheld from tokens that cannot update the conversation.
    - `reply_to_message_id` string, nullable, required: The earlier message this one quotes; null when it quotes none.
    - `attachments` object[], required: The files on the message, described without the connector's file ids, which are credentials.
      - `kind` string, nullable, required: What the file is: `photo`, `video`, `audio`, `voice`, `document`, `sticker` or `animation`.
      - `mime` string, nullable, required: The MIME type, when the platform gave one.
      - `file_name` string, nullable, required: The original file name, when the platform gave one.
      - `size` integer, nullable, required: The size in bytes, when known.
      - `width` integer, nullable, required: The width in pixels for an image or video; null otherwise.
      - `height` integer, nullable, required: The height in pixels for an image or video; null otherwise.
      - `duration` integer, nullable, required: The length in seconds for audio and video; null otherwise.
      - `url` string, nullable, required: The stored copy's URL, populated only after the file has been fetched at least once; null until then.
    - `failure_reason` string, nullable, required: Why an outbound message `failed` or is `unreachable`; null otherwise.
    - `edited_at` string, nullable, required: When the member edited the message, ISO 8601; the stored message is updated in place and no event fires. Null when never edited.
    - `read_at` string, nullable, required: When the team read an inbound message, ISO 8601; null while unread.
    - `created_at` string, nullable, required: When the message was recorded, ISO 8601.
  - `links` object, required: Links to the first, last, previous and next pages.
    - `first` string, nullable, required: The first page's URL.
    - `last` string, nullable, required: The last page's URL.
    - `prev` string, nullable, required: The previous page's URL; null on the first page.
    - `next` string, nullable, required: The next page's URL; null on the last page.
  - `meta` object, required: The paging counters for this page.
    - `current_page` integer, required: The page returned, 1-indexed.
    - `from` integer, nullable, required: The 1-indexed position of this page's first item across every page; null when the page is empty.
    - `last_page` integer, required: How many pages there are.
    - `links` object[], required: Generated paginator links.
      - `url` string, nullable, required: The page's URL; null for the ellipsis and the disabled arrows.
      - `label` string, required: The link's label: a page number, the previous or next arrow, or an ellipsis.
      - `active` boolean, required: Whether this link is the current page.
    - `path` string, nullable, required: Base path for paginator generated URLs.
    - `per_page` integer, required: Number of items shown per page.
    - `to` integer, nullable, required: Number of the last item in the slice.
    - `total` integer, required: Total number of items being paginated.

## Other responses

- `401`: `AUTHENTICATION_REQUIRED`: the request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an `sbt_test_` token on production).
- `403`: `TOKEN_MISSING_ABILITY`: the token is valid but does not carry the ability this endpoint requires; `error.context.required_ability` names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers `FORBIDDEN`, `TEAM_TIER_REQUIRED` or `CONNECTOR_TIER_REQUIRED` with the same status, and says so in its own description.
- `404`: `RESOURCE_NOT_FOUND`: an id in the path names nothing the token can see. `TENANT_MISMATCH`: the project sits outside the token's `scope:project:` allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.
- `429`: `RATE_LIMITED`: the token has spent its 300 requests a minute or 10,000 an hour; `Retry-After` says when the next one is accepted.

---

[API](https://skmtc.dev/memberpass/apis/subscriby-rest-api.md) · [All operations](https://skmtc.dev/memberpass/apis/subscriby-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/memberpass/apis/subscriby-rest-api/revisions/59c4df91d764?raw)
