Blue Reacher
Messages21 / 46

Messages

Unified send + list across every line. The `channel` field picks the pipeline.

Unified send + list across every line. The channel field picks the pipeline.

Every route takes Authorization: Bearer <ACCESS_TOKEN> unless the auth line says otherwise. Ids are numbers. Errors use the shape on the errors page.

RouteScopeWhat it does
GET /v1/messagesmessages.readList messages across any combination of channels — inbound + outbound — with filtering.
POST /v1/messagesmessages.writeSend an outbound message to a contact or a phone number, on any channel.
POST /v1/messages/{id}/reactionsmessages.writeSend an iMessage reaction (tapback) — ❤️ 👍 👎 😂 ‼️ ❓ — to a message in a contact's conversation.
POST /v1/messages/{id}/editmessages.writeEdit the text of an iMessage you sent, within 15 minutes — the recipient sees it as edited.
POST /v1/messages/{id}/unsendmessages.writeUnsend an iMessage you sent, within 2 minutes — it disappears from the recipient's conversation.
POST /v1/messages/{id}/notify-anywaymessages.writeBreak through the recipient's Focus for an iMessage you sent, within 24 hours (Apple's Notify Anyway).
GET /v1/messages/{id}messages.readCheck the delivery status of a message by its id (the message_id returned from Send message).
POST /v1/messages/scheduledmessages.writeSend a message later.
GET /v1/messages/scheduledmessages.readA workspace's scheduled messages.
DELETE /v1/messages/scheduled/{id}messages.writeCancel a message that has not been sent yet.

List messages

GET https://api.bluereacher.com/v1/messages

Auth: Bearer access token. Scope: messages.read.

List messages across any combination of channels — inbound + outbound — with filtering.

Returns the messages in the installer's workspaces, every channel in one list, from the same conversation records the app.bluereacher.com Conversations page shows. All filters are optional and combine with AND semantics.

One id everywhere. A row's id (and message_id, the same value as a string) is the message id the other message endpoints take: GET /messages/{id} for its status, POST /messages/{id}/reactions to react to it, and the id in the conversation thread. That holds for inbound messages too.

Order. One list across channels, ordered by created_at (newest first by default). breakdown counts the matching messages per channel; total is their sum.

Without workspace_id, every workspace the installer owns is listed.

Parameters

NameInTypeRequiredDescription
channelquerystringnoRestrict to one or more channels. Omit for all.
workspace_idquerynumbernoFilter to one workspace. Must belong to the installer.
phonequerystringnoFilter to messages exchanged with this phone number (E.164), or iMessage email address for iMessage — every channel.
statusquerystringnoSingle value or comma-separated list of statuses. Case-insensitive — ?status=Sent, ?status=SENT and ?status=sent all match. Values: "queued", "webhook_sent", "accepted", "sent", "delivered", "read", "failed", "received", "unsent".
pagequerynumbernoPage number (>= 1). Default 1. Anything else is a 400.
limitquerynumbernoPage size (1-100). Default 25. Anything else is a 400.
sortqueryenumnoSort by created_at — "created_at_asc" or "created_at_desc". Default "created_at_desc".

Request

curl -X GET "https://api.bluereacher.com/v1/messages?channel=sms%2Cimessage&workspace_id=7&phone=%2B15551234567" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK — interleaved across channels, newest first):

{
  "success": true,
  "data": {
    "messages": [
      {
        "id": 84220,
        "message_id": "84220",
        "channel": "imessage",
        "workspace_id": 7,
        "contact_id": 1234,
        "direction": "inbound",
        "to": null,
        "from": "+15551234567",
        "is_group": false,
        "text": "❤️ Loved: “Here is the brochure.”",
        "effect": null,
        "reaction": {
          "kind": "love",
          "emoji": "❤️",
          "snippet": "Here is the brochure."
        },
        "media": null,
        "status": "received",
        "error_message": null,
        "created_at": "2026-06-09T14:24:00.000Z",
        "updated_at": "2026-06-09T14:24:00.000Z"
      }
    ],
    "total": 87,
    "page": 1,
    "limit": 25,
    "breakdown": {
      "sms": 32,
      "imessage": 19
    }
  }
}
StatusWhenMessage
200OK — interleaved across channels, newest first
400Validation — bad sort keysort must be created_at_asc or created_at_desc.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): messages.read.
404workspace_id is not accessible to this tokenWorkspace not found or not accessible to this token
500Unexpected server errorFailed to list messages.

Response fields

messages: Array of messages, normalized across channels. Fields:

FieldTypeDescription
idnumberThe message id. The same id works with Get message status, React to message, and in the conversation thread. Example: 84213
message_idstringThe same id as a string — the message_id a Send message response returns. Example: 84213
channelenumExample: imessage
workspace_idnumberThe workspace this message belongs to. Example: 7
contact_idnumber, nullableThe contact the message was sent to / received from. Null for group messages. Example: 1234
directionenum"outbound" (sent from the workspace) or "inbound" (received). Example: outbound
tostring, nullableOutbound: the contact's phone (E.164), or iMessage email address for iMessage. Null for inbound messages. Example: +15551234567
fromstring, nullableInbound: the contact's phone or iMessage email address — in a group, the member who wrote it. Null for outbound messages.
is_groupbooleanTrue for a message in a group conversation (iMessage group). Example: false
textstring (text), nullableThe message body. May be null when only media was sent.
effectstring, nullableThe iMessage send effect on the message (either direction), e.g. "confetti" or "slam"; null when there is none. The text then starts with a "✦ Effect: <name>" line.
reactionobject, nullableSet when the message is an iMessage reaction (tapback) to another message, in either direction: { kind, emoji, snippet }. kind is love | like | dislike | laugh | emphasize | question, or "emoji" for a custom-emoji reaction from a contact; snippet is the start of the message reacted to. Null for any other message. The text is the reaction line, e.g. "❤️ Loved: “See you at 5?”".
mediaarray<{url,type}>, nullableMedia attachments, or null when there are none.
statusstring, nullablequeued | webhook_sent | accepted | sent | delivered | read | failed | received | unsent.
error_messagestring, nullableWhy a failed message failed; null otherwise.
created_atstring (ISO 8601)When the message was created.
updated_atstring (ISO 8601), nullableWhen the message was last updated.

Send message

POST https://api.bluereacher.com/v1/messages

Auth: Bearer access token. Scope: messages.write.

Limits: 30 messages / 15 min per workspace · 1 attachment per message, 5 MB max

Send an outbound message to a contact or a phone number, on any channel.

Before you can send: on app.bluereacher.com → Devices, add a device (iMessage) and assign it to the workspace. A workspace with no assigned device for an eligible channel records the message but does not deliver it.

Supply contact_id or phone (with country code, e.g. +61 / +1 — a contact is auto-created if none matches), plus message and/or attachments — a single media URL (attachment-only sends are valid).

iMessage to an email address: iMessage also reaches an iMessage email address. Send it as email, or put the email in phone. If no contact has that email, an email-only contact is auto-created, the same as for a new phone number. A contact that has a phone number is always messaged at the phone; an email-only contact (by contact_id too) is messaged at its email over iMessage.

Omit channel (or send default) to use the workspace Message Routing (Primary → Fallback; same-row channels in parallel), or force one with channel = imessage. The send is recorded in the conversation / Message Logs.

mp3, m4a/aac, ogg/opus and wav work (mp3 is the safe choice), one file up to 5 MB at a public https:// URL that answers a HEAD request with Content-Length and an audio/* content type. message is optional and becomes the caption or an accompanying text. Delivery is asynchronous as for any send; replies and reactions come back as ordinary inbound messages.

Send effects (iMessage): add effect to send the message with an iMessage effect — a full-screen one (confetti, fireworks, balloons, hearts, lasers, shooting_star, sparkles, echo, spotlight) or a bubble one (slam, loud, gentle, invisible_ink). An effect sends over iMessage (leave channel out or send imessage; another channel is a 400), needs message text, and needs a line with Advanced Mode on in the workspace — the same rule as the effect button on the dashboard; without one the request is a 400 NO_ADVANCED_MODE_LINE. In message reads the effect is the effect field (also on messages a contact sends with an effect). The stored text keeps the effect as its first line, ✦ Effect: confetti, as the dashboard writes it; the recipient sees only the body.

Threaded replies (iMessage): add reply_to with a message id to answer that message the way the reply button on the app.bluereacher.com does. The message is sent with a leading line, ↩︎ Replying to “<the first 60 characters of that message>” (“an attachment” for a photo or file), which a line in Advanced Mode turns into a real threaded reply; the contact sees only your text. Leave the recipient out and the reply goes to that message's contact. Replies are iMessage only, need message text, can't answer a group message or a reaction, and need a line with Advanced Mode on (else 400 NO_ADVANCED_MODE_LINE). With effect too, the effect line comes first. The line finds the target by its quoted text, so if two messages in the thread start the same way, the reply attaches to the one Messages picks.

Parameters

NameInTypeRequiredDescription
workspace_idbodynumberyesThe workspace to send from. Must belong to the installer. Its Message Routing decides the channel(s) + device when channel is omitted.
contact_idbodynumbernoThe contact to send to (must exist in the workspace). Provide this, phone or email — at least one is required.
phonebodystringnoRecipient phone with country code (e.g. +61…, +1…). Provide this, contact_id or email. If no contact with this number exists in the workspace, one is auto-created and the message is sent to it. iMessage only: an iMessage email address is accepted here too, and is treated as email.
emailbodystringnoiMessage only. An iMessage email address to message over iMessage, when there is no contact_id or phone. Another channel is a 400. If no contact has this email, an email-only contact is auto-created.
channelbodyenumno(type is accepted as an alias.)
messagebodystring (text)noThe message body. Required unless attachments is provided. text is accepted as a legacy alias.
attachmentsbodystring (URL)noOptional media as a single URL string — 1 attachment per message, file size up to 5 MB. Send with or instead of message; an attachment-only send is valid. Sending an array with more than one URL is rejected with a 400. (media is accepted as a legacy alias for this field.)
effectbodyenumnoAn iMessage send effect. Screen effects: confetti, fireworks, balloons, hearts, lasers, shooting_star, sparkles, echo, spotlight. Bubble effects: slam, loud, gentle, invisible_ink. iMessage only, needs message text and a line in Advanced Mode on the workspace — see the description.
reply_tobodynumbernoSend the message as an iMessage threaded reply to this message id (a List messages / conversation message id, or a Send message message_id). iMessage only, needs message text and a line in Advanced Mode on the workspace. With no recipient, the reply goes to that message's contact; a different recipient is a 400.

Request

curl -X POST "https://api.bluereacher.com/v1/messages" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7,
  "phone": "+61412345678",
  "channel": "default",
  "message": "Thanks for your enquiry — we open at 09:00.",
  "attachments": ""
}'

Responses

A 200 reply (OK — queued for delivery):

{
  "success": true,
  "message": "Message queued for delivery.",
  "data": {
    "id": 84213,
    "status": "webhook_sent",
    "message_id": "84213",
    "conversation_id": 512,
    "channel": "imessage",
    "queued_at": "2026-07-20T10:22:07.000Z"
  }
}
StatusWhenMessage
200OK — queued for delivery
400Validation — no recipient (need contact_id, phone or email)Provide contact_id, phone or email.
400An email recipient with a channel other than iMessageEmail addresses can only be messaged over iMessage.
400Validation — malformed emailemail must be a valid email address.
400Validation — neither message nor attachments suppliedmessage or attachments is required.
400Validation — more than one attachment suppliedOnly one attachment is allowed per message (max 5 MB).
400Effect — not iMessageEffects are iMessage only: send channel imessage (or leave channel out).
400Effect — no line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Send effects need a line with Advanced Mode on.
400Effect — unknown name, or no message texteffect must be one of: confetti, fireworks, balloons, hearts, lasers, shooting_star, sparkles, echo, spotlight, slam, loud, gentle, invisible_ink
400Reply — not iMessage, a group message, a reaction, or nothing to reply toReplies are iMessage only: the reply_to message was not sent over iMessage.
400Reply — the recipient is not the reply_to message's contactreply_to is a message in another conversation: a reply goes to the same contact.
400Reply — no line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Replies need a line with Advanced Mode on.
404Reply — reply_to is not a message in this workspacereply_to message not found
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): messages.write. This integration was granted: …
404workspace / contact not found or not accessible to this tokenContact not found in this workspace
409Recipient has outbound Do-Not-Disturb activeCannot send message as DND is active
429Rate limit exceeded — too many queued sends for this workspace (30 messages / 15 min)Too many queued messages for this workspace
502The message could not be delivered to the messaging provider — retryableFailed to forward message to the gateway.
503Message sending is not available for this accountOutbound gateway is not configured.
500Unexpected server errorFailed to queue message for delivery.

Response fields

send_result: The queued outbound message. Fields:

FieldTypeDescription
idnumberThe id of the queued message — use it to correlate delivery-status callbacks. Example: 84213
statusstringDelivery status immediately after the send is accepted — typically "webhook_sent", or "failed". Example: webhook_sent
message_idstringString form of the message id — use it to correlate delivery-status callbacks / webhook events. Example: 84213
conversation_idnumber, nullableThe conversation this message belongs to, when known. Example: 512
channelstring, nullableThe forced channel, or null when the workspace routing decided it. Example: imessage
queued_atstring (ISO 8601)When the message row was created / queued. Example: 2026-07-20T10:22:07.000Z
reply_tostringOnly on a threaded reply: the id of the message replied to. Example: 84214

React to message

POST https://api.bluereacher.com/v1/messages/{id}/reactions

Auth: Bearer access token. Scope: messages.write.

Limits: 30 messages / 15 min per workspace (counts with Send message)

Send an iMessage reaction (tapback) — ❤️ 👍 👎 😂 ‼️ ❓ — to a message in a contact's conversation.

Reacts to a message the way the reaction bar on the app.bluereacher.com conversation does. {id} is the message's id: the id of a row from List messages or List conversation messages, or the message_id from Send message. Messages you sent and messages the contact sent can both be reacted to.

How it is sent: a reaction is an iMessage whose text is one line, ❤️ Loved: “<the message reacted to>”. The quote is the start of the target's text — up to 60 characters, spaces and line breaks collapsed, with "…" when it is cut. A line in Advanced Mode turns that line into a real tapback on the quoted message; the contact never sees the text. It goes to the message's contact through the same pipeline as Send message, so DND, credits and the send rate limit apply as for any message, and the response is the same.

Rules (the same as the dashboard's):

  • The message must be an iMessage with text, in a one-to-one conversation.

The line finds the target by its quoted text, so when the conversation holds two messages that start the same way, the tapback lands on the one Messages picks.

In message reads a reaction is the reaction field — { kind, emoji, snippet } — on reactions you send and on the contact's, which also carry custom emoji (kind: "emoji").

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe id of the message to react to — a List messages or conversation message id, or the message_id from Send message.
workspace_idbodynumberyesThe workspace the message belongs to.
reactionbodyenumyeslove ❤️, like 👍, dislike 👎, laugh 😂, emphasize ‼️ or question ❓.

Request

curl -X POST "https://api.bluereacher.com/v1/messages/84214/reactions" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7,
  "reaction": "love"
}'

Responses

A 200 reply (OK — reaction queued for delivery):

{
  "success": true,
  "message": "Message queued for delivery.",
  "data": {
    "id": 84230,
    "status": "webhook_sent",
    "message_id": "84230",
    "conversation_id": 512,
    "channel": "imessage",
    "queued_at": "2026-10-27T09:16:00.000Z",
    "reaction": "love",
    "reacted_to_message_id": "84214"
  }
}
StatusWhenMessage
200OK — reaction queued for delivery
400Validation — unknown reactionreaction must be one of: love, like, dislike, laugh, emphasize, question
400Validation — no workspace_idworkspace_id is required
400The message is not an iMessageReactions are iMessage only: this message was not sent over iMessage.
400The message has no text (attachment only)This message has no text to react to.
400The message is itself a reactionA reaction can't be reacted to.
400The message is in a group conversationReactions to group messages are not supported.
400No line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Reactions need a line with Advanced Mode on.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): messages.write. This integration was granted: …
404Message not found in this workspace (or not accessible to this token)Message not found
409The contact has outbound Do-Not-Disturb activeCannot send message as DND is active
429Rate limit exceeded (30 messages / 15 min per workspace)Too many queued messages for this workspace
502The reaction could not be delivered to the messaging provider — retryableFailed to forward message to the gateway.

Response fields

send_result: The queued reaction message — the Send message result, plus what it reacted to. Fields:

FieldTypeDescription
idnumberThe reaction message's id. Use it with Get message status. Example: 84230
statusstringDelivery status immediately after the send is accepted — typically "webhook_sent", or "failed". Example: webhook_sent
message_idstringString form of the reaction message's id. Example: 84230
channelstringAlways "imessage". Example: imessage
reactionstringThe reaction sent. Example: love
reacted_to_message_idstringThe id of the message reacted to. Example: 84214

Edit message

POST https://api.bluereacher.com/v1/messages/{id}/edit

Auth: Bearer access token. Scope: messages.write.

Edit the text of an iMessage you sent, within 15 minutes — the recipient sees it as edited.

Edits a sent iMessage the way the edit button on the app.bluereacher.com conversation does: the line that sent it edits it in Messages, and the recipient sees the new text marked Edited. Apple allows edits within 15 minutes of sending (and up to five edits).

Send the new body in message. If the message was sent with an effect, a subject or as a threaded reply, those stay as they were; only the body changes. The edited text is what message reads return afterwards.

Rules (the same as the dashboard's): the message must be one you sent, over iMessage, with text, sent from a line, and not itself a reaction; the workspace needs a line with Advanced Mode on (else 400 NO_ADVANCED_MODE_LINE). The request waits for the line (up to 15 s): 422 LINE_REFUSED when Messages refused, 503 LINE_UNREACHABLE when the line is offline, 504 LINE_TIMEOUT when it did not answer in time — the change may still land, so read the message again before retrying.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe id of the message — a List messages or conversation message id, or the message_id from Send message.
workspace_idbodynumberyesThe workspace the message belongs to.
messagebodystring (text)yesThe new text. text is accepted as an alias.

Request

curl -X POST "https://api.bluereacher.com/v1/messages/84213/edit" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7,
  "message": "Booking confirmed for 5 PM."
}'

Responses

A 200 reply (OK — done on the line):

{
  "success": true,
  "message": "Message edited",
  "data": {
    "id": 84213,
    "message_id": "84213",
    "channel": "imessage",
    "workspace_id": 7,
    "contact_id": 1234,
    "direction": "outbound",
    "to": "+61412345678",
    "from": null,
    "is_group": false,
    "text": "Booking confirmed for 5 PM.",
    "effect": null,
    "reaction": null,
    "media": null,
    "status": "delivered",
    "error_message": null,
    "created_at": "2026-10-29T09:15:58.000Z",
    "updated_at": "2026-10-29T09:20:03.000Z",
    "edited_at": "2026-10-29T09:20:03.000Z"
  }
}
StatusWhenMessage
200OK — done on the line
400Outside Apple's windowMessages can only be edited within 15 minutes of sending
400Not an iMessage you sent with textOnly messages you sent can be changed
400No line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Edit, unsend and Notify Anyway need a line with Advanced Mode on.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope: one of messages.send, messages.write. This integration was granted: …
404Message not found in this workspace (or not accessible to this token)Message not found
422Messages on the line refused the changeThe line couldn't edit the message
503The line that sent the message is not connectedThe line isn't connected right now
504The line did not answer within 15 s — the change may still land; read the message againThe line didn't answer in time. Check the thread in a moment.

Unsend message

POST https://api.bluereacher.com/v1/messages/{id}/unsend

Auth: Bearer access token. Scope: messages.write.

Unsend an iMessage you sent, within 2 minutes — it disappears from the recipient's conversation.

Unsends a sent iMessage the way the unsend button on the app.bluereacher.com conversation does. Apple allows unsending within 2 minutes of sending. The message's status becomes unsent afterwards.

A recipient on an older iOS / macOS may still keep the original.

Rules (the same as the dashboard's): the message must be one you sent, over iMessage, with text, sent from a line, and not itself a reaction; the workspace needs a line with Advanced Mode on (else 400 NO_ADVANCED_MODE_LINE). The request waits for the line (up to 15 s): 422 LINE_REFUSED when Messages refused, 503 LINE_UNREACHABLE when the line is offline, 504 LINE_TIMEOUT when it did not answer in time — the change may still land, so read the message again before retrying.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe id of the message — a List messages or conversation message id, or the message_id from Send message.
workspace_idbodynumberyesThe workspace the message belongs to.

Request

curl -X POST "https://api.bluereacher.com/v1/messages/84213/unsend" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7
}'

Responses

A 200 reply (OK — done on the line):

{
  "success": true,
  "message": "Message unsent",
  "data": {
    "id": 84213,
    "message_id": "84213",
    "channel": "imessage",
    "workspace_id": 7,
    "contact_id": 1234,
    "direction": "outbound",
    "to": "+61412345678",
    "from": null,
    "is_group": false,
    "text": "Booking confirmed for 4 PM.",
    "effect": null,
    "reaction": null,
    "media": null,
    "status": "unsent",
    "error_message": null,
    "created_at": "2026-10-29T09:15:58.000Z",
    "updated_at": "2026-10-29T09:20:03.000Z",
    "edited_at": null
  }
}
StatusWhenMessage
200OK — done on the line
400Outside Apple's windowMessages can only be unsent within 2 minutes of sending
400Not an iMessage you sent with textOnly messages you sent can be changed
400No line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Edit, unsend and Notify Anyway need a line with Advanced Mode on.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope: one of messages.send, messages.write. This integration was granted: …
404Message not found in this workspace (or not accessible to this token)Message not found
422Messages on the line refused the changeThe line couldn't unsend the message
503The line that sent the message is not connectedThe line isn't connected right now
504The line did not answer within 15 s — the change may still land; read the message againThe line didn't answer in time. Check the thread in a moment.

Notify anyway

POST https://api.bluereacher.com/v1/messages/{id}/notify-anyway

Auth: Bearer access token. Scope: messages.write.

Break through the recipient's Focus for an iMessage you sent, within 24 hours (Apple's Notify Anyway).

When the recipient has a Focus on, Messages silences the notification and shows "has notifications silenced". Notify Anyway pushes that message's notification through once, as the app.bluereacher.com button does. Apple allows it within 24 hours of sending. The message itself does not change.

To see whether a recipient has notifications silenced first, use Check iMessage (silenced).

Rules (the same as the dashboard's): the message must be one you sent, over iMessage, with text, sent from a line, and not itself a reaction; the workspace needs a line with Advanced Mode on (else 400 NO_ADVANCED_MODE_LINE). The request waits for the line (up to 15 s): 422 LINE_REFUSED when Messages refused, 503 LINE_UNREACHABLE when the line is offline, 504 LINE_TIMEOUT when it did not answer in time — the change may still land, so read the message again before retrying.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe id of the message — a List messages or conversation message id, or the message_id from Send message.
workspace_idbodynumberyesThe workspace the message belongs to.

Request

curl -X POST "https://api.bluereacher.com/v1/messages/84213/notify-anyway" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7
}'

Responses

A 200 reply (OK — done on the line):

{
  "success": true,
  "message": "Notified anyway",
  "data": {
    "id": 84213,
    "message_id": "84213",
    "channel": "imessage",
    "workspace_id": 7,
    "contact_id": 1234,
    "direction": "outbound",
    "to": "+61412345678",
    "from": null,
    "is_group": false,
    "text": "Booking confirmed for 4 PM.",
    "effect": null,
    "reaction": null,
    "media": null,
    "status": "delivered",
    "error_message": null,
    "created_at": "2026-10-29T09:15:58.000Z",
    "updated_at": "2026-10-29T09:20:03.000Z",
    "edited_at": null
  }
}
StatusWhenMessage
200OK — done on the line
400Outside Apple's windowNotify Anyway is only available within 24 hours of sending
400Not an iMessage you sent with textOnly messages you sent can be re-notified
400No line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Edit, unsend and Notify Anyway need a line with Advanced Mode on.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope: one of messages.send, messages.write. This integration was granted: …
404Message not found in this workspace (or not accessible to this token)Message not found
422Messages on the line refused the changeThe line couldn't re-notify the message
503The line that sent the message is not connectedThe line isn't connected right now
504The line did not answer within 15 s — the change may still land; read the message againThe line didn't answer in time. Check the thread in a moment.

Get message status

GET https://api.bluereacher.com/v1/messages/{id}

Auth: Bearer access token. Scope: messages.read.

Check the delivery status of a message by its id (the message_id returned from Send message).

Look up a single message by its id — the message_id returned from Send message, or the id of any List messages or conversation thread row — and read its current delivery status. Scoped to your token, so you can only read your own messages.

The response returns the message_id, channel, status and message, with effect and reaction (see List messages). Status lifecycle: queued → webhook_sent → accepted → sent → delivered (or failed).

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe message id — the message_id returned from POST /messages.

Request

curl -X GET "https://api.bluereacher.com/v1/messages/84213" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK — current status):

{
  "success": true,
  "data": {
    "message_id": "84213",
    "channel": "imessage",
    "status": "delivered",
    "message": "Thanks for your enquiry — we open at 09:00.",
    "effect": null
  }
}
StatusWhenMessage
200OK — current status
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): messages.read. This integration was granted: …
404Message not found (or not accessible to this token)Message not found

Response fields

message: The message record with its current delivery status. Fields:

FieldTypeDescription
message_idstringThe message id (matches what Send message returned). Example: 84213
channelstring, nullableChannel the message went out on (null until routing resolves it). Example: imessage
statusstringqueued | webhook_sent | accepted | sent | delivered | failed | received. Example: delivered
messagestring, nullableMessage body.

Schedule message

POST https://api.bluereacher.com/v1/messages/scheduled

Auth: Bearer access token. Scope: messages.write.

Limits: 30 messages / 15 min per workspace (counts with Send message) · 1 attachment per message

Send a message later.

Same recipient and channel rules as Send message. send_at is an ISO 8601 time at least 1 minute and at most 1 year ahead. The message goes out within a minute of send_at; credits, DND, routing and the device are checked then, not now — a message that cannot be sent at that time ends as failed with the reason in error.

An effect works as on Send message; the iMessage and Advanced Mode checks are made when you schedule it.

Parameters

NameInTypeRequiredDescription
workspace_idbodynumberyesThe workspace to send from.
contact_idbodynumbernoThe contact. Or send phone / email.
phonebodystringnoRecipient number with country code.
emailbodystringnoAn iMessage email address (iMessage only).
messagebodystringnoThe text. Required unless an attachment is sent.
attachmentsbodystring (URL)noOne public file URL.
channelbodyenumnoAs for Send message; omit to use Message Routing.
send_atbodystring (ISO 8601)yesWhen to send, UTC.
effectbodyenumnoAn iMessage send effect. Screen effects: confetti, fireworks, balloons, hearts, lasers, shooting_star, sparkles, echo, spotlight. Bubble effects: slam, loud, gentle, invisible_ink. iMessage only, needs message text and a line in Advanced Mode on the workspace — see the description.

Request

curl -X POST "https://api.bluereacher.com/v1/messages/scheduled" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7,
  "contact_id": 1234,
  "message": "Reminder: your call is tomorrow at 10am.",
  "send_at": "2026-10-28T23:00:00Z"
}'

Responses

A 201 reply (Scheduled):

{
  "success": true,
  "message": "Message scheduled",
  "data": {
    "id": 912,
    "workspace_id": 7,
    "contact_id": 1234,
    "to": "+61412345678",
    "message": "Reminder: your call is tomorrow at 10am.",
    "effect": null,
    "reaction": null,
    "attachments": [],
    "channel": null,
    "send_at": "2026-10-28T23:00:00.000Z",
    "status": "pending",
    "sent_message_id": null,
    "error": null,
    "created_at": "2026-10-27T09:20:00.000Z"
  }
}
StatusWhenMessage
201Scheduled
400Bad time, no recipient, or no textPick a time at least a minute from now
400Effect — not iMessageEffects are iMessage only: send channel imessage (or leave channel out).
400Effect — no line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. Send effects need a line with Advanced Mode on.
400Effect — unknown name, or no message texteffect must be one of: confetti, fireworks, balloons, hearts, lasers, shooting_star, sparkles, echo, spotlight, slam, loud, gentle, invisible_ink
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope: one of messages.send, messages.write. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token
429Workspace send limit reachedToo many queued messages for this workspace

List scheduled messages

GET https://api.bluereacher.com/v1/messages/scheduled

Auth: Bearer access token. Scope: messages.read.

A workspace's scheduled messages.

status defaults to pending (waiting or being sent now), soonest first. Any other status lists newest first.

Parameters

NameInTypeRequiredDescription
workspace_idquerynumberyesThe workspace.
statusqueryenumnoDefault pending.
contact_idquerynumbernoOnly this contact.
pagequerynumbernoDefault 1.
limitquerynumberno1–100, default 50. Anything else is a 400.

Request

curl -X GET "https://api.bluereacher.com/v1/messages/scheduled?workspace_id=7" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "data": [
    {
      "id": 912,
      "workspace_id": 7,
      "contact_id": 1234,
      "to": "+61412345678",
      "message": "Reminder: your call is tomorrow at 10am.",
      "effect": null,
      "reaction": null,
      "attachments": [],
      "channel": null,
      "send_at": "2026-10-28T23:00:00.000Z",
      "status": "pending",
      "sent_message_id": null,
      "error": null,
      "created_at": "2026-10-27T09:20:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "max_limit": 100,
    "total": 1,
    "total_pages": 1
  }
}
StatusWhenMessage
200OK
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): messages.read. This integration was granted: …
404Workspace does not exist or is not owned by the installer (same response for both)Workspace not found or not accessible to this token

Cancel scheduled message

DELETE https://api.bluereacher.com/v1/messages/scheduled/{id}

Auth: Bearer access token. Scope: messages.write.

Cancel a message that has not been sent yet.

Only a pending message can be cancelled. One already being sent, sent, failed or cancelled answers 409.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe scheduled message id.

Request

curl -X DELETE "https://api.bluereacher.com/v1/messages/scheduled/912" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "message": "Scheduled message cancelled"
}
StatusWhenMessage
200OK
401Missing or invalid tokenInvalid or expired access token.
404Scheduled message does not exist or is not owned by the installer (same response for both)Scheduled message not found or not accessible to this token
409Already sent or being sentThis message is already sent

On this page