> ## Documentation Index
> Fetch the complete documentation index at: https://docs.staging.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](https://docs.staging.relayapp.im/api-reference/messages/send-a-message-to-an-existing-chat.md)); 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](https://docs.staging.relayapp.im/live/authentication.md).

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](https://docs.staging.relayapp.im/agents/blocked-handles.md) 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:

**Preview**

An agent message as the person sees it

**JSON**

```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](https://docs.staging.relayapp.im/messages/parts.md) 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]
>
> The app draws the inline syntax below in text parts it receives and hides the delimiters; the chat list row and the push banner show the same words. A person's own messages are shown as typed. Block syntax such as headings, lists, and fenced code is shown as written. Mentions keep their highlight inside formatted text.

| 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:

**Preview**

The six Markdown formats as the app draws them

**JSON**

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

The [Chat SDK adapter](https://docs.staging.relayapp.im/integrations/chat-sdk.md#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`](https://docs.staging.relayapp.im/events/message-received) and [`message.sent`](https://docs.staging.relayapp.im/events/message-sent).

## Resolve or create a Chat

Call `POST /v1/messages` ([reference](https://docs.staging.relayapp.im/api-reference/messages/resolve-a-chat-and-send-a-message.md)) 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](https://docs.staging.relayapp.im/agents/message-requests.md).

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](https://docs.staging.relayapp.im/live/idempotency.md) covers key length and lifetime.

## When it fails

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

## Next steps

* [Build message parts](https://docs.staging.relayapp.im/messages/parts.md)
* [Reply to a message](https://docs.staging.relayapp.im/messages/replies.md)
* [Read delivery receipts](https://docs.staging.relayapp.im/messages/receipts.md)
* [Retry safely with idempotency](https://docs.staging.relayapp.im/live/idempotency.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.