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

# Message formatting and limits

> Text length, media types and size caps, voice memos, link handling, emoji encoding, and exactly what survives when a message falls back from iMessage to RCS or SMS.

Every message you send through BlueReacher targets one of three channels: `imessage`, `rcs`, or `sms`. The three do not accept the same content. This page tells you what each one carries, what gets rewritten on the way down, and what to build so a single payload works on all of them.

## Text

Message text goes in the `content` field as UTF-8. Whitespace is preserved, including line breaks (`\n`). There is no markdown rendering on any channel. Asterisks stay asterisks.

### Length caps

| Channel  | Hard cap on `content` | Behavior at the cap                                |
| -------- | --------------------- | -------------------------------------------------- |
| iMessage | 20,000 characters     | Request rejected with `content_too_long`           |
| RCS      | 3,072 characters      | Request rejected with `content_too_long`           |
| SMS      | 1,600 characters      | Delivered as multiple segments, billed per segment |

Caps are not targets. For a first touch on a cold thread, stay between 90 and 320 characters. Past roughly 400 characters an iMessage bubble stops fitting on one screen, and reply rates on multi-screen opening messages drop hard. Save the long version for the reply.

### SMS segment math

SMS is the only channel where character count costs money. The encoding your text triggers decides how many characters fit per segment.

| Encoding | Single message | Per segment when split | Triggered by                                                                                                |
| -------- | -------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- |
| GSM-7    | 160 chars      | 153 chars              | Plain ASCII letters, digits, basic punctuation                                                              |
| UCS-2    | 70 chars       | 67 chars               | Any emoji, curly quote, ellipsis character, em dash or en dash character, accented letter, non-Latin script |

One curly apostrophe pasted from a doc editor cuts your SMS capacity by more than half. Strip smart punctuation before you send: replace curly quotes with straight quotes, the ellipsis character with three periods, and long dash characters with a comma or a period. In GSM-7, the characters `^ { } [ ] ~ \ |` and the euro sign each count as two.

## Emoji

iMessage and RCS render the full current Unicode emoji set, including skin tone and multi-person sequences. SMS renders whatever the receiving handset supports, so emoji added after roughly 2021 can land as an empty box on older Android devices.

Two rules that matter operationally:

* One emoji in an SMS-fallback message costs you 90 characters of capacity. Decide whether it earns that.
* A skin tone modifier or a family sequence is several code points, not one character. A single such emoji can consume 7 to 11 characters of your budget.

Emoji in the `content` field never affect iMessage deliverability. They affect SMS cost and SMS rendering only.

## Media

Attach files with `media_url`. BlueReacher fetches the file, stores a copy, and sends that copy. One `media_url` per message. To send several files, send several messages 2 to 4 seconds apart.

Your `media_url` must:

* Use HTTPS with a valid certificate
* Return HTTP 200 within 10 seconds, with no authentication challenge and no redirect chain longer than two hops
* Send an accurate `Content-Type` header (this is how the file type is detected, not the file extension)
* Stay reachable for at least 60 minutes after the request if it is a signed URL

### Supported types and size limits

| Type     | Accepted formats           | API max | Delivered on iMessage          | Delivered on RCS                     | SMS fallback                |
| -------- | -------------------------- | ------- | ------------------------------ | ------------------------------------ | --------------------------- |
| Image    | JPEG, PNG, GIF, HEIC, WebP | 100 MB  | Up to 100 MB, original quality | Up to 10 MB, recompressed above that | Downscaled to fit 500 KB    |
| Video    | MP4 (H.264 + AAC), MOV     | 100 MB  | Up to 100 MB                   | Up to 10 MB, transcoded              | Replaced with a hosted link |
| Audio    | M4A, CAF, MP3, WAV, AMR    | 25 MB   | Up to 25 MB                    | Up to 10 MB                          | Replaced with a hosted link |
| Document | PDF                        | 25 MB   | Up to 25 MB                    | Replaced with a hosted link          | Replaced with a hosted link |

The practical target for anything you want to look identical on all three channels is an image under 500 KB. A 1200 x 1200 JPEG at quality 80 lands near 250 KB and fills the bubble on every device. Animated GIFs should stay under 3 MB.

For video, encode H.264 baseline profile with AAC audio, keep it under 30 seconds, and keep the file under 10 MB. That clears iMessage and RCS intact and keeps the SMS link small enough to load on a weak connection.

### Voice memos

To render as a playable voice memo bubble on iMessage rather than a generic file attachment, send `.caf` or `.m4a` with mono audio at 22 kHz or lower. MP3 and WAV files attach as documents and lose the waveform and the inline play button.

Keep voice memos under 60 seconds. Anything past two minutes is usually not played. On RCS the same file arrives as an audio attachment with a plain play control. On SMS it becomes a link.

## Links

A bare URL in `content` renders as a rich preview card on iMessage. The preview is built on the recipient's device from your page's Open Graph tags, not by BlueReacher. For the card to appear you need `og:title`, `og:description`, and an `og:image` under 1 MB on a page that returns 200 to an anonymous request. If your page sits behind a bot filter or a cookie wall, the card fails and the recipient sees a plain blue link.

Put the URL on its own line at the end of the message. A URL in the middle of a sentence still previews, but the card pushes the rest of your copy down.

### Why public URL shorteners hurt you

Do not send `bit.ly`, `tinyurl.com`, or any other shared shortener domain. Four concrete reasons:

1. Reputation is shared. Carrier SMS filters score the domain, not your account. Every spam campaign that used that shortener this month is part of your score.
2. Several public shortener domains are already on US carrier blocklists. The message is dropped silently and you are billed for it.
3. Each redirect hop is another chance for the preview fetch to time out. Two hops means the iMessage card usually fails to build.
4. Recipients cannot see the destination. A hidden destination in an unsolicited message reads as a scam, which drives the report rate that governs your line health.

Use a subdomain you control, like `go.yourcompany.com`, with a valid certificate and exactly one redirect. Send it on warm threads first. Never put a link in the first message of a cold thread.

## What survives the fallback

When a recipient is not reachable on iMessage, the message steps down to RCS, then to SMS, based on your line settings. Content is rewritten at each step. Assume the SMS version is what a recipient will see and write the copy so it still works there.

| Feature           | iMessage                       | RCS                            | SMS                               |
| ----------------- | ------------------------------ | ------------------------------ | --------------------------------- |
| Plain text        | Up to 20,000 chars             | Up to 3,072 chars              | Up to 1,600 chars, segmented      |
| Emoji             | Full support                   | Full support                   | Handset-dependent, costs capacity |
| Line breaks       | Yes                            | Yes                            | Yes                               |
| Images            | Up to 100 MB                   | Up to 10 MB                    | Downscaled to 500 KB              |
| Animated GIF      | Yes, animated                  | Yes, animated                  | First frame only                  |
| Video             | Up to 100 MB inline            | Up to 10 MB, transcoded        | Hosted link                       |
| Voice memo bubble | Yes, with waveform             | Audio file, plain player       | Hosted link                       |
| PDF               | Yes, inline                    | Hosted link                    | Hosted link                       |
| Link preview card | Yes                            | Yes                            | No, raw URL                       |
| Typing indicator  | Yes                            | Yes                            | No                                |
| Read receipts     | Yes, if recipient enables them | Yes, if recipient enables them | No                                |
| Delivery receipt  | Yes                            | Yes                            | Carrier-level only                |
| Inbound reactions | Tapbacks delivered as events   | Reactions delivered as events  | Text like "Liked ..."             |
| Blue bubble       | Yes                            | No                             | No                                |

Every BlueReacher line is a dedicated iMessage line, managed for you, with no A2P registration required. The fallback channels carry the same content rules described above.

## Sending media

```bash theme={null}
curl -X POST https://api.bluereacher.com/functions/v1/messages \
  -H "Authorization: Bearer bluereacher_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+14155550142",
    "to": "+14155550199",
    "content": "Here is the 40 second walkthrough I mentioned.",
    "channel": "imessage",
    "media_url": "https://cdn.yourcompany.com/clips/walkthrough.mp4",
    "external_id": "seq_412_step_3"
  }'
```

```json theme={null}
{
  "id": "msg_01J9K2WQ7T3X0RCPB4M6ZN8VDA",
  "line_id": "line_01J8ZQ4C7B2R9YKF3H6TMXW5PN",
  "contact_id": "cnt_01J8ZR6D9F4S1MTV5J7QKXB2HC",
  "from": "+14155550142",
  "to": "+14155550199",
  "content": "Here is the 40 second walkthrough I mentioned.",
  "channel": "imessage",
  "media_url": "https://cdn.yourcompany.com/clips/walkthrough.mp4",
  "external_id": "seq_412_step_3",
  "status": "queued",
  "created_at": "2026-07-24T16:22:08Z"
}
```

`status` returns `queued` because media is fetched after the request returns. Watch the message webhook for `sent`, `delivered`, or `failed`.

## Errors

| HTTP | `error.code`             | Cause                                                        | Fix                                               |
| ---- | ------------------------ | ------------------------------------------------------------ | ------------------------------------------------- |
| 400  | `media_url_unreachable`  | Fetch returned non-200, timed out past 10s, or required auth | Serve the file over public HTTPS with no auth     |
| 415  | `media_unsupported_type` | `Content-Type` is not in the supported table                 | Set the correct header on your file host          |
| 413  | `media_too_large`        | File over the API max for its type                           | Compress before uploading to your host            |
| 422  | `content_too_long`       | `content` exceeds the cap for `channel`                      | Shorten, or split into two messages               |
| 422  | `content_required`       | Both `content` and `media_url` empty                         | Send at least one of the two                      |
| 429  | `rate_limited`           | Line send rate exceeded                                      | Back off and retry using the `Retry-After` header |

A failed media fetch fails the whole message. Text is not sent on its own as a partial result.
