> ## 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.

# Text formatting

> Send and receive native bold, italic, underline, and strikethrough.

Chert includes native text formatting for iMessage. Send plain text in `value`
and describe styles with `text_decorations`; Markdown asterisks remain literal.

> [!NOTE]
>
> Formatting is an existing line-enabled preview. Confirm access with Chert before
> using it. The initial scope is one text part in an existing phone-addressed
> iMessage direct chat. Group messages, replies, attachments, SMS/RCS, and animated
> text effects are outside this preview. Other lines can reject decorated requests
> with code `4099`; do not assume every Chert API host or SDK accepts them.

## Send formatted text

Use `POST /api/v1/chats/{chat_id}/messages` on the enabled line. Save this body
as `formatted-message.json` and use a stable idempotency key for this operation:

```json theme={null}
{
  "message": {
    "idempotency_key": "format-four-styles-001",
    "parts": [{
      "type": "text",
      "value": "Bold Italic Underline Strike",
      "text_decorations": [
        { "range": [0, 4], "style": "bold" },
        { "range": [5, 11], "style": "italic" },
        { "range": [12, 21], "style": "underline" },
        { "range": [22, 28], "style": "strikethrough" }
      ]
    }]
  }
}
```

```bash cURL theme={null}
curl "https://console.trychert.com/api/v1/chats/$CHAT_ID/messages" \
  -H "Authorization: Bearer $CHERT_SIGNING_SECRET" \
  -H "Content-Type: application/json" \
  --data-binary @formatted-message.json
```

```js Node.js theme={null}
import { readFile } from "node:fs/promises";
const response = await fetch(
  `https://console.trychert.com/api/v1/chats/${process.env.CHAT_ID}/messages`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.CHERT_SIGNING_SECRET}`,
      "Content-Type": "application/json"
    },
    body: await readFile("formatted-message.json", "utf8")
  }
);
const result = await response.json();
// Inspect response.status and result; acceptance is not delivery.
```

```python Python theme={null}
import os, requests
with open("formatted-message.json", "rb") as body:
    response = requests.post(
        f"https://console.trychert.com/api/v1/chats/{os.environ['CHAT_ID']}/messages",
        headers={
            "Authorization": f"Bearer {os.environ['CHERT_SIGNING_SECRET']}",
            "Content-Type": "application/json",
        },
        data=body.read(),
        timeout=30,
    )
result = response.json()  # Inspect status_code; acceptance is not delivery.
```

## Range rules

* `range` is `[start, end)`: zero-based UTF-16 code units, with an exclusive end.
* Supported styles are `bold`, `italic`, `underline`, and `strikethrough`.
* Ranges must be nonempty, inside `value`, and must not split a surrogate pair.
  JavaScript string offsets use UTF-16; Python character offsets need conversion
  when the text contains characters outside the Basic Multilingual Plane.
* Different styles can overlap. Equivalent adjacent/overlapping ranges of the
  same style are combined. At most 256 input decorations are accepted.
* Preserve the exact text used to calculate offsets. This path does not trim or
  normalize the text before applying styles.

## Acceptance, status, and inbound formatting

A new accepted request returns HTTP `202` with a `message` object containing
`id`, `chat_id`, the decorated `parts`, and `status: "queued"`. Save `message.id`
and use `GET /api/v1/messages/{id}` to inspect recorded status. Neither a queued
receipt nor a delivery status proves the recipient rendered each style.

Reuse the same key and identical text/styles when reconciling the original
operation. Changing the request under that key conflicts. An unconfirmed result
with `retryable: false` must not trigger another send or a new key.

On enabled lines, `message.received.data.message.parts[]` and recorded chat
history can contain the same `text_decorations` shape. Keep `value` as readable
plain text when your client cannot render styles. Missing decorations do not
establish that the sender used no formatting.

| Failure | What to do |
| - | - |
| Invalid style/range (`1002`) | Correct the request before creating a new operation. |
| Unsupported line or chat (`4099`) | Confirm preview access and use an eligible existing direct chat. |
| Conflicting idempotency key (HTTP `409`) | Reconcile the original operation; do not reuse its key for different content. |
| Unconfirmed outcome (`4103`, `retryable: false`) | Inspect recorded status and contact Chert before sending again. |

See [Send a message](https://docs.trychert.com/api/chats/send-message.md) and
[Receiving replies](https://docs.trychert.com/api/receiving-replies.md).


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