Skip to main content
Plain text is one part of an iMessage thread. These six endpoints send the rest: the typing bubble, the read receipt, tapbacks, voice memos, and contact cards. They use the same base URL, the same API key, and the same field names as the messaging endpoints. Every feature on this page is native to iMessage. When a thread is not on iMessage, the request still succeeds and BlueReacher tells you what it did instead. See iMessage only, and what happens elsewhere.

Endpoints at a glance

Base URL and authentication

All requests go to https://api.bluereacher.com/functions/v1/ and are POST with a JSON body.
Your API key covers every line on your account. Call these endpoints from your server, never from a browser or a mobile app, because the key can send on any of your lines.

Identifying the line and the recipient

Every endpoint on this page takes one sender and one recipient.
  • from is one of your dedicated iMessage lines in E.164 format, for example +13105550142. Lines are managed for you, so you only need the number.
  • line_id is the same line by its BlueReacher id, for example line_7c2a9d41. Use it when your line numbers can change.
  • to is the recipient number in E.164 format.
  • contact_id is a contact record already stored in BlueReacher. BlueReacher resolves it to the number on file.
Sending both from and line_id, or both to and contact_id, returns 400 invalid_request. None of these endpoints accept a channel field in the request. The features only exist on iMessage, so the channel is decided for you and returned in the response. To send something over another channel when iMessage is not available, use the fallback field described below.

iMessage only, and what happens elsewhere

When the thread is not on iMessage, BlueReacher does not throw an error and does not silently drop your call. It returns 200 with "status": "skipped" and a skipped_reason, or it downgrades the send if you asked for a fallback. The fallback field takes two values on /send-reaction, /send-voice-note, and /send-contact-card: Skipped calls cost nothing. Fallback sends are billed as one message on the channel that carried them. skipped_reason values: To check before you call, read the channel field on the inbound message or on the message you are replying to. It is "imessage", "rcs", or "sms".

POST /send-typing-indicator

Shows the animated typing bubble in the recipient’s thread. Use it before a reply so the conversation reads like a person on the other end.
Requires Authorization: Bearer bluereacher_your_api_key and Content-Type: application/json.

Request fields

The bubble clears when duration elapses or as soon as you send a message on that line, whichever comes first. There is no stop call. A natural pace is roughly one second of typing per 15 characters of the reply, capped at 12 seconds. Longer than that reads as a stall.

Response fields

Example request

Example response

Errors

POST /mark-read

Sends a read receipt for inbound messages in a thread. Your contact sees “Read” with a timestamp under the last message they sent.
Requires Authorization: Bearer bluereacher_your_api_key and Content-Type: application/json.

Request fields

Read receipts only travel in one direction: this endpoint reports that your line read their message. It does not tell you whether they read yours. Delivery and read events on your outbound messages arrive by webhook.

Response fields

Example request

Example response

Errors

A thread with no unread inbound messages returns 200 with "messages_marked": 0 and "status": "skipped".

POST /send-reaction

Adds or removes a tapback on a specific message. You can react to messages you received and to messages you sent.
Requires Authorization: Bearer bluereacher_your_api_key and Content-Type: application/json.

Supported tapbacks

Fallback text quotes the target message and truncates it at 120 characters followed by an ellipsis. For media messages the quote is replaced by the file name.

Request fields

One reaction per message per line. Sending a second reaction to the same message replaces the first, and the recipient sees the change in place. "action": "remove" clears your reaction and requires the same reaction value you sent originally.

Response fields

Example request

Example response

Skipped example

Errors

POST /send-voice-note

Sends an audio file that renders as an inline voice memo with a waveform and a play button, not as a file attachment.
Requires Authorization: Bearer bluereacher_your_api_key and Content-Type: application/json.

Request fields

Audio is converted to mono AAC at 32 kbps before sending, which is what makes it render as a voice memo instead of an attachment. The file at media_url is left untouched. Accepted formats: .m4a, .aac, .mp3, .wav, .caf. Maximum 16 MB and 300 seconds. Full limits are in Supported formats and size limits. Voice notes create a real message, so they appear in message history and emit the standard delivery webhooks. One behavior to plan around: with default iMessage settings, audio messages disappear from the thread two minutes after the recipient plays them unless they tap Keep. Anything the recipient needs to refer back to, such as a link, a price, or a time, should also go out as text.

Response fields

Example request

Example response

Errors

POST /send-contact-card

Sends a vCard that renders as a tappable contact card. The recipient can add it to their contacts in one tap, which is the cleanest way to hand over a rep’s details or a calendar contact.
Requires Authorization: Bearer bluereacher_your_api_key and Content-Type: application/json.

Request fields

Card rules:
  • vCard 3.0 renders most reliably. vCard 4.0 is accepted and converted to 3.0 before sending.
  • BEGIN:VCARD, VERSION, FN, and END:VCARD are required. Cards without FN are rejected.
  • In JSON, write line breaks as \n. BlueReacher normalizes them to the CRLF the vCard format expects.
  • PHOTO may be base64 JPEG or PNG. Keep it under 20 KB so the card stays inside the 32 KB inline limit.
  • One card per request. To send several, send several messages.
When you pass vcard inline, BlueReacher hosts a copy and returns its media_url, so you can reuse the same card without rebuilding it.

Response fields

Example request

Example response

Errors

POST /upload-media

Hosts a file and returns a reusable media_url. Upload once, send to as many recipients and from as many lines as you want.
Requires Authorization: Bearer bluereacher_your_api_key and Content-Type: application/json.

Request fields

Request bodies over 20 MB are rejected, which caps file at roughly 14 MB of source bytes because base64 adds about a third. Use source_url for anything larger. Uploading identical bytes with the same purpose returns the existing record instead of storing a second copy, so retrying an upload is safe. media_url is stable and reusable. It expires 12 months after the last send that used it, and every new send resets that clock.

Response fields

Example request

Example response

Errors

Supported formats and size limits

Notes:
  • Every JSON request body is capped at 20 MB across all endpoints.
  • media_url and source_url must be HTTPS and must serve the file without authentication.
  • HEIC and WebP images send as they are over iMessage. On an SMS or RCS fallback they are converted to JPEG so every recipient can open them.
  • Audio is converted to mono AAC at 32 kbps for voice note sends. Files stored through /upload-media keep their original bytes.

Rate limits

Over the limit returns 429 with a Retry-After header in seconds. Retry after that many seconds with a small random delay added so parallel workers do not all come back at once.

Idempotency with external_id

external_id is unique per account. Sending the same external_id twice within 24 hours returns the original record with the original created_at instead of performing the action again. Use it on any call you might retry after a timeout.

Error format

Every error returns a JSON body with the same shape.
Codes shared by every endpoint on this page: Retry 500, 503, and 429. Do not retry 400, 401, 403, 404, 413, 415, or 422 without changing the request.

Webhooks

/send-voice-note and /send-contact-card create messages, so they emit the same message.sent, message.delivered, and message.failed webhooks as any other send, keyed by id and external_id. Typing indicators, read receipts, and reactions do not create messages and do not emit outbound webhooks. Inbound tapbacks from your contacts do arrive, as reaction.received events carrying message_id, reaction, from, and created_at.

Sending a natural voice note reply

Upload once, show the typing bubble, then send.

Reacting to an inbound message

Handle a message.received webhook and tapback when the reply is a yes.
The webhook payload carries channel, so you can check for "imessage" before calling and skip the round trip on SMS threads.

Sending on your lines

Rich messaging runs on your dedicated iMessage lines, managed for you, with no A2P registration required. The lines behave like any other conversation thread, which is why tapbacks, read receipts, and voice memos land the way your contacts expect.