POST /v1/chats/{chatId}/messages (reference); the SDK method is relay.chats.messages.send. When you hold only the recipient handles, resolve or create the chat instead. Authenticate requests as described in 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 decide which recipients get a copy, and a withheld copy raises no error.
Send to an existing Chat
Send the body with anIdempotency-Key header:
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 has the rules for each part type.
Markdown
Send Markdown source inside a text part’svalue. The API stores and returns the source unchanged.
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.
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:
{ 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. Setsilent on the message body:
silent: true.
The same field appears in message.received and message.sent.
Resolve or create a Chat
CallPOST /v1/messages (reference) with to when you have no chat ID:
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.
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
SendIdempotency-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 covers key length and lifetime.
When it fails
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 lists the rest.

