Endpoints at a glance
Base URL and authentication
All requests go tohttps://api.bluereacher.com/functions/v1/ and are POST with a JSON body.
Identifying the line and the recipient
Every endpoint on this page takes one sender and one recipient.fromis 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_idis the same line by its BlueReacher id, for exampleline_7c2a9d41. Use it when your line numbers can change.tois the recipient number in E.164 format.contact_idis a contact record already stored in BlueReacher. BlueReacher resolves it to the number on file.
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 returns200 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.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.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.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.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.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, andEND:VCARDare required. Cards withoutFNare rejected.- In JSON, write line breaks as
\n. BlueReacher normalizes them to the CRLF the vCard format expects. PHOTOmay 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.
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 reusablemedia_url. Upload once, send to as many recipients and from as many lines as you want.
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_urlandsource_urlmust 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-mediakeep 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 amessage.received webhook and tapback when the reply is a yes.
channel, so you can check for "imessage" before calling and skip the round trip on SMS threads.