---
title: "Start welcome message"
method: POST
path: "/v6/messages/welcome/start"
tags: ["Messages (v6)"]
---

# Start welcome message

`POST /v6/messages/welcome/start`

## Request

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

Returns the started message plus a signed `stream_key`. Clients open the existing application websocket and authenticate the audio-upload session with this key (same flow as the legacy v3 stream-key behavior). The `stream_key` is bound to `message.id` and expires according to the websocket gateway configuration.

## Request body

- StartWelcomeMessage
  - `transcript` string, nullable: The transcript if the client generated one, if is_text_message is true then this text will be used to generate andio using text-to-speech
  - `is_text_message` boolean, required: If true the server will generate audio based on the transcript provided
  - `unique_client_id` string, required: A unique id the client can use to identify the message, server will prevent duplicates using it
  - `release_date` string, date-time, nullable: The date the message should be released (Not yet implemented)
  - `utm_data` UtmData
    - `utm_source` string
    - `utm_medium` string
    - `utm_campaign` string
    - `utm_term` string
    - `utm_content` string
  - `is_streaming` boolean, required: If the message is being streamed than notifications are sent to listeners at the begining of the message
  - `announce_user` boolean, nullable: Only used if is_text_message is true, prepends <first name said> to transcript before text-to-speech
  - `voice` string, nullable: the voice to use when doing text to speech
  - `kind` 'audio' | 'text' | 'attachment' | 'action-item' | 'ai-prompt' | 'ai-response' | 'channel-reminder'
  - `workspace_id` string, required
  - `is_voicemail` boolean, required

## Response `201`

- CreateStreamMessageV6Response
  - `message` MessageV6, required
    - `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.
  - `stream_key` string, required: Signed key the client must use to authenticate the websocket audio upload session for this message.

## Other responses

- `400`
- `403`: Caller is not a workspace admin

---

[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)
