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

# Send a message

> POST /api/v1/chats/:id/messages - send a follow-up in an existing chat.

Sends a follow-up in an existing chat. This is a chat-scoped route: `{id}` is the `chat_id`, not a `message_id`.

<Warning>
  The body is wrapped in `message`. Top-level `parts` will be rejected.
</Warning>

For group chats, [create the group](/api/group-chats/create) with a text-only `POST /api/v1/chats` call
first. Send media and rich links through this follow-up endpoint after the
group chat exists.

## Request

```bash theme={null}
curl -X POST https://console.trychert.com/api/v1/chats/$CHAT_ID/messages \
  -H "Authorization: Bearer $CHERT_SIGNING_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "message": {
      "parts": [{ "type": "text", "value": "How about 3pm PT?" }],
      "idempotency_key": "followup-2026-05-01-002"
    }
  }'
```

## Send media

Upload first, then reference the `attachment_id`.

```json theme={null}
{
  "message": {
    "parts": [
      { "type": "text", "value": "See attached." },
      { "type": "media", "attachment_id": "9f3b27a8c14d4a6f8e2b91d4c5e6f7a8" }
    ]
  }
}
```

## Send a rich link

The `rich_link` part shape is the same on every Chert sender line. The rich link is rendered as its own preview bubble.

```json theme={null}
{
  "message": {
    "parts": [
      { "type": "text", "value": "Leaving this here." },
      { "type": "rich_link", "url": "https://example.com/demo" }
    ]
  }
}
```

Optional fields: `title`, `summary`, `image_url`, `icon_url`.

## Send media with a rich link

This is the recommended shape for review-request messages that include a
personalized image and a previewed URL.

```json theme={null}
{
  "message": {
    "parts": [
      { "type": "media", "attachment_id": "9f3b27a8c14d4a6f8e2b91d4c5e6f7a8" },
      { "type": "text", "value": "Hi Marcus, this is Todd from Texas Prime Plumbing. I would really appreciate a Google review." },
      { "type": "rich_link", "url": "https://search.google.com/local/writereview?placeid=..." }
    ]
  }
}
```

## Response

```json theme={null}
{
  "message": {
    "id": "46eb1003c8b54b7ea8f1c2b03e9a7d12",
    "chat_id": "0f2d3c1a-8b4e-4f6a-90d2-1a3b4c5d6e7f",
    "parts": [{ "type": "text", "value": "How about 3pm PT?" }],
    "status": "sent",
    "direction": "outbound",
    "created_at": "2026-05-01T14:30:00Z",
    "delivered_at": null,
    "read_at": null,
    "service": "imessage"
  }
}
```

The returned `message.id` is the id to pass to message-scoped actions such as
[`POST /api/v1/messages/{id}/react`](/api/messages/react).

## Fields

| Field                     | Required | Notes                                                                                                                                                                                            |
| ------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Path `id`                 | Yes      | The `chat.id` returned by [`POST /api/v1/chats`](/api/chats/create). Do not pass `message.id` or `convo_id` here.                                                                                |
| `message.parts`           | Yes      | Array of `text`, `media`, and `rich_link` parts. Text parts use `value`; media parts reference an uploaded `attachment_id`; rich-link parts use `{ "type": "rich_link", "url": "https://..." }`. |
| `message.idempotency_key` | No       | Safe retry key scoped to the tenant.                                                                                                                                                             |

## See also

* [Create a chat](/api/chats/create)
* [Attachments](/api/attachments)
* [List messages](/api/chats/list-messages)
