---
title: "Get messages by IDs"
method: POST
path: "/v6/messages/by-ids"
tags: ["Messages (v6)"]
---

# Get messages by IDs

`POST /v6/messages/by-ids`

## Request

- Base URL: `https://api.carbonvoice.app`
- URL: `https://api.carbonvoice.app/v6/messages/by-ids`
- Auth: one of:
  - API key in header `pxtoken`
  - OAuth 2 (implicit, authorization URL `https://api.carbonvoice.app/oauth/authorize`)

Returns a list of messages (MessageV6) by IDs, in request order. With `conversation_id` the user must have access to that conversation and only its messages are returned. Without it the ids may span conversations and voice memos; each message is checked on its own and any the user cannot access, or that do not exist, are silently left out. MessageV6 differs from v5 in three ways: `thread_id` (the parent id, or the message id itself when it is not a reply) replaces `parent_message_id`; the audio rendition and its transcript, AI summary, language flags and time codes are nested under `content`, with the waveform as a compact base-36 string; and the requesting user's own state (`heard_ms`, `label_ids`, `notify`, `notes`, `last_heard_update`) is included where the read path carries it.

## Request body

- GetMessagesByIdsV5Payload
  - `conversation_id` string: Conversation (channel) ID. When set, the user must have access to this conversation and only its messages are returned. When omitted, messages may come from any conversation (or be voice memos) and each is checked on its own; messages the user cannot access, or that do not exist, are left out.
  - `message_ids` string[], required: List of message IDs to fetch. Results keep this order; ids that are not returned are simply absent.
  - `language` string: Language for message content (e.g. transcript, audio). Original language used if not provided.
  - `presigned_url` boolean: Include presigned URLs for audio files (default: false)
  - `fresh` boolean: Bypass cache and fetch fresh data (default: false)

## Response `200`

- MessageV6[]
  - `id` string, required: Message ID
  - `type` 'channel' | 'prerecorded' | 'voicememo' | 'stored' | 'welcome', required: Message type
  - `kind` 'audio' | 'text' | 'attachment' | 'action-item' | 'ai-prompt' | 'ai-response' | 'channel-reminder', required
  - `name` string: User-assigned name (title) of the message. Omitted when the message has none.
  - `created_at` string, date-time, required: Creation timestamp
  - `updated_at` string, date-time, required: Last update timestamp
  - `deleted_at` string, date-time: Deletion timestamp
  - `conversation_id` string: Conversation ID
  - `workspace_id` string, required: Workspace ID
  - `creator_id` string, required: Creator ID
  - `status` 'offline' | 'paused' | 'processing' | 'scheduled' | 'active' | 'deleted' | 'account-deleted' | 'initializing' | 'inprogress' | 'canceled' | 'failed', required
  - `audio_delivery` 'recording' | 'streaming', required
  - `thread_id` string, required: ID of the thread this message belongs to: the parent message id for a reply, or the message's own id when it is not a reply. A message is a reply exactly when `thread_id !== id`.
  - `idempotency_key` string: Optional canonical idempotency key surfaced when the underlying message data carries one. Not guaranteed to be present on every message.
  - `attachments` AttachmentV6[]: List of attachments for the message
    - `presigned_url` string, nullable: Presigned URL for direct S3 access
    - `presigned_url_expiration_date` string, date-time, nullable: Expiration date for the presigned URL
    - `id` string, required: Attachment ID
    - `idempotency_key` string, nullable: Optional attachment-level idempotency key. Surfaced when the underlying attachment was created with a client-supplied `idempotency_key` (legacy `client_id`).
    - `creator_id` string, required: Creator ID
    - `created_at` string, date-time, required: Creation timestamp
    - `type` 'link' | 'file' | 'location' | 'ai-response-id' | 'ai-prompt-id' | 'action-item-id' | 'ask-id', required
    - `url` string, required: URL/Link to the attachment
    - `filename` string, nullable: Filename of the attachment
    - `mime_type` string, nullable: MIME type of the attachment
    - `length_in_bytes` number, nullable: Size of the attachment in bytes
    - `status` 'Initializing' | 'Uploading' | 'Uploaded' | 'Failed'
    - `percent_complete` number, nullable: Upload progress percentage (0-100) for the attachment. Surfaced when the underlying attachment row carries one.
    - `latitude` number, double, nullable: Latitude of a location attachment
    - `longitude` number, double, nullable: Longitude of a location attachment
  - `available_languages` string[]: List of available languages for the message
  - `original_language` string: The language the message was recorded in
  - `ai_response_ids` MessageAIResponse[]: List of AI response IDs associated with the message
    - `id` string, required: AI Response ID
    - `prompt_id` string, required: Prompt ID
  - `share_link_id` string: Share Link ID to a message
  - `link` string, required: Link to Message
  - `folder_id` string: Folder ID where the message is stored
  - `utm_data` UtmDataV5
    - `utm_source` string, nullable: UTM source parameter
    - `utm_medium` string, nullable: UTM medium parameter
    - `utm_campaign` string, nullable: UTM campaign parameter
    - `utm_content` string, nullable: UTM content parameter
    - `utm_term` string, nullable: UTM term parameter
  - `conversation_sequence` number: Sequence number of the message in the conversation
  - `source_message_id` string: Source message ID if this is a forwarded message
  - `content` MessageContentV6
    - `presigned_url` string, nullable: Presigned URL for direct S3 access
    - `presigned_url_expiration_date` string, date-time, nullable: Expiration date for the presigned URL
    - `id` string: The audio id of this rendition. Send it back as `content_id` to update it (e.g. `PUT /v6/messages/transcript`). Omitted when the message has no audio yet.
    - `ai_summary` string, nullable: AI summary of the message in this language
    - `transcript` string, nullable: Transcript of the message in this language
    - `time_codes` MessageTimeCode[]: Word-level time codes for this rendition
      - `t` string, required: Text/word for the time code
      - `s` number, required: Start time in milliseconds
      - `e` number, required: End time in milliseconds
    - `is_original_language` boolean, nullable: Whether this rendition is the language the message was recorded in
    - `language` string, nullable: Language of this rendition (transcript, AI summary, audio)
    - `url` string, nullable: URL to the audio file
    - `streaming_url` string, nullable: URL to the streaming audio file
    - `duration_ms` number, nullable: Duration of the audio in milliseconds
    - `waveform_percentage` string, nullable: Waveform amplitudes encoded as a compact string: one base-36 character per bar (`0` = silence .. `z` = full scale), at most 96 bars. Decode each character with `parseInt(ch, 36) / 35`. Omitted when the rendition has no waveform.
  - `users_caught_up` 'all' | 'some' | 'none': Users caught up status for the message
  - `reaction_summary` ReactionSummaryV6
    - `reaction_counts` object, required: Reaction counts by reaction ID
    - `top_user_reactions` UserReactionV5[], required: Top user reactions
      - `user_id` string, required: User ID
      - `reaction_id` string, required: Reaction ID
    - `top_user_emojis` TopUserEmojiV6[]: Every reaction (curated as its canonical emoji, plus arbitrary emoji), grouped per emoji. Authoritative when present, even when empty; absent only on summaries persisted before the field existed, in which case fall back to `top_user_reactions`.
      - `reaction` string, required: Canonical unicode emoji (e.g. ❤️, 🎉)
      - `count` number, required: Total number of distinct users with this reaction (never capped)
      - `user_ids` string[], required: A capped preview of the users who reacted with this emoji, not the full list
  - `users_not_allowed_to_receive_notifications` UserNotAllowedReceiveNotification[]: Users not allowed to receive notifications for this message
    - `user_id` string, required: User ID
    - `phone` string, nullable: Phone number
    - `email` string, nullable: Email address
  - `source` 'email_ingestion' | 'reminder_user_id': Where the message came from, when it was not recorded in the app
  - `source_value` string: Source-specific value (e.g. the ingested email address)
  - `tagged_user_ids` string[], required: IDs of users tagged in the message
  - `heard_ms` number: How far the requesting user has listened, in milliseconds. Only present when the message was read on behalf of a user.
  - `label_ids` string[]: Label IDs the requesting user applied to the message. Only present when the message was read on behalf of a user.
  - `notify` boolean: Whether the message is still in the requesting user's notifications (unheard). Only present when the message was read on behalf of a user.
  - `notes` string: Private notes the requesting user attached to the message. Only present when the message was read on behalf of a user.
  - `last_heard_update` string, date-time: Last time the requesting user's listen state or notes for this message changed. Only present when the message was read on behalf of a user.

## Other responses

- `400`
- `403`

---

[API](https://skmtc.dev/carbonvoice/apis/carbon-voice-api.md) · [All operations](https://skmtc.dev/carbonvoice/apis/carbon-voice-api/llms.txt) · [OpenAPI document](https://skmtc.dev/carbonvoice/apis/carbon-voice-api/revisions/b91c5c845122?raw)
