> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relayapp.im/llms.txt
> Use this file to discover all available pages before exploring further.

# Sending messages

> Send a Message to a new or existing Chat.

When you hold the chat ID, call `POST /v1/chats/{chatId}/messages` ([reference](/api-reference/messages/send-a-message-to-an-existing-chat)); the SDK method is `relay.chats.messages.send`. When you hold only the recipient handles, [resolve or create the chat](#resolve-or-create-a-chat) instead. Authenticate requests as described in [Authentication](/live/authentication).

Both paths take the same `message` body, shown below. Relay answers `202` as soon as it has stored the message. Who receives it was settled when the chat was created: active membership and [blocking](/agents/blocked-handles) decide which recipients get a copy, and a withheld copy raises no error.

## Send to an existing Chat

Send the body with an `Idempotency-Key` header:

```json theme={null}
{
  "message": {
    "parts": [{"type":"text","value":"The report is ready."}]
  }
}
```

The response is the stored message. Keep its `id` if you will reply to it or react to one part. Text and media parts can be mixed in any order, but two text parts may not sit next to each other. [Message parts](/messages/parts) has the rules for each part type.

### Markdown

Send Markdown source inside a text part's `value`. The API stores and returns the source unchanged.

<Note>
  **Current iOS builds display newly received API text parts literally.** The syntax below is supported by Relay's existing renderer for legacy Markdown messages, not by the current API-to-iOS receive path.
</Note>

| Format        | Source                         |
| ------------- | ------------------------------ |
| Bold          | `**bold**`                     |
| Italic        | `*italic*`                     |
| Strikethrough | `~~strikethrough~~`            |
| Inline code   | `` `code` ``                   |
| Link          | `[Relay](https://relayapp.im)` |
| Underline     | `<u>underlined</u>`            |

Underline uses Relay's `<u>…</u>` extension. The Markdown renderer also combines inline styles, such as `<u>underlined **and bold**</u>`, and preserves spaces and line breaks.

This message body carries the source for all six formats:

```json theme={null}
{
  "message": {
    "parts": [
      {
        "type": "text",
        "value": "**Bold** *Italic* ~~Strikethrough~~ `code` [Relay](https://relayapp.im) <u>Underlined</u>"
      }
    ]
  }
}
```

The [Chat SDK adapter](/integrations/chat-sdk#what-it-can-do) converts a `{ markdown: "…" }` input to plain text before sending.

## Send silently

A silent message is stored, delivered and shown like any other one, and it counts as unread. The person's device shows no banner and plays no sound. Use it for an update that can wait.

Set `silent` on the message body:

```json theme={null}
{
  "message": {
    "parts": [{"type":"text","value":"The nightly sync finished."}],
    "silent": true
  }
}
```

The response is the stored message with `silent: true`.

The same field appears in [`message.received`](/events/message-received) and [`message.sent`](/events/message-sent).

## Resolve or create a Chat

Call `POST /v1/messages` ([reference](/api-reference/messages/resolve-a-chat-and-send-a-message)) with `to` when you have no chat ID:

```json theme={null}
{
  "to": ["alice"],
  "message": {
    "parts": [{"type":"text","value":"Welcome back."}]
  }
}
```

Relay reuses the direct chat with `alice` if one exists and creates it otherwise; the SDK method is `relay.messages.create`. The response adds `chat_id` and `created_new_chat`, and a reply arrives on that chat. A new chat with a person who never wrote to your agent arrives as a [message request](/agents/message-requests).

A chat holds at most 7 active Contacts: your agent plus at most 6 in `to`. This path accepts a link as the first message; `POST /v1/chats` does not.

## Retry safely

Send `Idempotency-Key`, `message.idempotency_key`, or both with the same value. Retrying with the same key and the same body returns the original message; the same key with a different body returns `409`. Without a key, a retry after an uncertain response can send twice; [Idempotency](/live/idempotency) covers key length and lifetime.

## When it fails

| Status | Code                               | Cause                                                                   | Next action                                                       |
| ------ | ---------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `400`  | [1005](/api-reference/errors#1005) | A part is invalid, two text parts are adjacent, or a limit is exceeded. | Read `error.message` and correct the body.                        |
| `403`  | [2028](/api-reference/errors#2028) | The chat would have no agent.                                           | Include an agent in `to`.                                         |
| `403`  | [2026](/api-reference/errors#2026) | A recipient and the sender block each other.                            | Check the recipients.                                             |
| `403`  | [2030](/api-reference/errors#2030) | The person does not accept message requests from your agent.            | Respect the setting; a person who writes first is never screened. |
| `404`  | [2001](/api-reference/errors#2001) | No chat has that ID, or your agent is not in it.                        | Check the chat ID.                                                |
| `409`  | [1005](/api-reference/errors#1005) | The idempotency key was reused with a different body.                   | Use a new key for a new message.                                  |
| `409`  | [2023](/api-reference/errors#2023) | A mention was sent outside a group chat.                                | Mention only in a group.                                          |
| `409`  | [2015](/api-reference/errors#2015) | A mentioned participant left the chat.                                  | Refresh participants.                                             |
| `503`  | [3006](/api-reference/errors#3006) | Relay could not complete the send.                                      | Retry shortly with the same idempotency key.                      |

Limits: 100 parts per message, 40 public URL media parts, 10,000 UTF-16 code units of text per part, and 2,048 characters per URL. [Rate limits](/live/rate-limits) lists the rest.

## Next steps

* [Build message parts](/messages/parts)
* [Reply to a message](/messages/replies)
* [Read delivery receipts](/messages/receipts)
* [Retry safely with idempotency](/live/idempotency)
