---
title: "Send a message"
method: POST
path: "/messages"
---

# Send a message

`POST /messages`

## Request

- Base URL: `https://osis.co/api/v1/comms`
- URL: `https://osis.co/api/v1/comms/messages`
- Auth: HTTP bearer

Send a text from your Comms line over iMessage, RCS, or SMS. Scope: `comms_send`.

## Headers

- `Idempotency-Key` string

## Request body

- SendMessageRequest: Say who to send to with to, contact_id, or conversation_id. Then add body, attachments, or both.
  - `to` string: Phone number to send to. Required unless you set contact_id or conversation_id. Use E.164, or set default_country for a local number. For RCS, this must be an E.164 number.
  - `body` string: The message text. Required unless you send attachments.
  - `conversation_id` string: A one-on-one or group conversation to send in. Required unless you set to or contact_id. Group messages stay on iMessage and on the group's original line. Text and attachments both work.
  - `reply_to_message_id` string: The message to reply to in an iMessage thread. Needs conversation_id. Thread replies stay on iMessage. Changing this on a retry with the same idempotency key returns 409.
  - `channel` 'auto' | 'sms' | 'imessage' | 'rcs' | 'whatsapp': auto (default) tries iMessage, then RCS, then WhatsApp, then SMS, all from the same number. RCS is only tried for plain text sent to a phone number. WhatsApp is only tried for text or files when the number has WhatsApp turned on and the recipient is on WhatsApp. Comms only moves to the next channel when the last one clearly rejected the message. Timeouts and unclear results never cause a second send. If you pick a channel, only that channel is used. RCS needs a supported dedicated line and doesn't work with contact_id, conversation_id, attachments, polls, or thread replies. channel whatsapp needs a number with WhatsApp turned on, in from or line_e164, and carries text up to 4096 characters, attachments, and thread replies.
  - `line_e164` string: The number to send from, in E.164 format. You can also call it from. Agent keys can pick any line attached to the agent. By default, replies use the conversation's line and new messages use the agent's primary line. A workspace key limited to one line can only use that line.
  - `from` string: Another name for line_e164.
  - `idempotency_key` string: Same as the Idempotency-Key header.
  - `attachments` object[]: Files to send, up to 9 MiB total after decoding. Carriers and phones have their own limits too. contentType and dataBase64 also work.
    - `filename` string, required
    - `content_type` string
    - `data_base64` string, byte, required
  - `contact_id` string: A contact you already have. Required unless you set to or conversation_id.
  - `default_country` string: Country code, only needed if the number is local and has no country code.
  - `whatsapp_template` object: Meta-approved template: name, language.code, optional components containing one body with text parameters. Only for channel=whatsapp.
    - `name` string, required
    - `language` object, required
      - `code` string, required
    - `components` object[]

## Response `200`

Already sent with this idempotency key. Returns the first message.

- SendMessageResponse
  - `message` Message
    - `id` string
    - `body` string
    - `direction` 'outbound' | 'inbound'
    - `conversation_id` string
    - `reply_to_message_id` string: The ID of the message this replies to, if it's in this conversation.
    - `thread_root_message_id` string: The first message in this thread.
    - `channel` 'sms' | 'imessage' | 'rcs' | 'whatsapp'
    - `status` string
    - `contact_id` string
    - `line_id` string: Line ID when available.
    - `line_e164` string: Your number in this conversation: the number that received the message, or the number you sent from.
    - `to` string
    - `read_at` string, date-time: The native read time when a read receipt is available. For one-to-one iMessage and RCS, the recipient must have read receipts on. Never available for SMS; absence does not mean unread.
    - `created_at` string, date-time
    - `audience` 'direct' | 'shared': Whether the message is in a group conversation or a one-on-one conversation.
    - `author` object: Who sent the message. Display names aren't verified.
      - `contact_id` string, required
      - `external_id` string, required
      - `display_name` string
    - `reply_to_provider_message_id` string: Another ID for the message this replies to, when available.
    - `thread_originator_guid` string: Another ID for the first message in the thread, when available.
    - `attachments` InboundAttachment[]: Files someone sent you. If a message is only files, body is empty.
      - `id` string
      - `filename` string, required
      - `content_type` string, required
      - `mediaType` string, required
      - `size_bytes` integer
      - `transcription` string
      - `url` string, uri: Where to download the file. Needs an API key with comms_read from the same workspace and line.
    - `unsent_at` string, date-time: When the unsend was confirmed. The original text and delivery history are kept.
  - `duplicate` boolean

## Other responses

- `202`: Accepted. Not delivered yet.
- `401`: API key is missing or wrong
- `403`: Your key doesn't have the scope this needs
- `429`: Too many requests. Slow down and retry.

---

[API](https://skmtc.dev/osis/apis/comms-api.md) · [All operations](https://skmtc.dev/osis/apis/comms-api/llms.txt) · [OpenAPI document](https://skmtc.dev/osis/apis/comms-api/revisions/59a4c0ba8936?raw)
