Skip to main content
send-message delivers one message to one recipient. It tries iMessage first, falls back to RCS, then to SMS, and returns immediately with a message id you can track. Use it for one-off sends, CRM-triggered follow-ups, and anything an agent or workflow fires in real time. The call is asynchronous. A 200-class response means BlueReacher accepted the message and queued it, not that the recipient has it. Delivery state arrives on your webhook.

Endpoint

Per-line send pacing is handled for you. Queue as fast as the rate limit allows and BlueReacher spaces the actual sends to protect your line.

Authentication

Every request carries a bearer token:
Keys start with bluereacher_ and are scoped to one workspace. Create and rotate them in the dashboard under Settings, API keys. Send requests from your server only, never from a browser or mobile client. A missing, malformed, or revoked key returns 401.

Request fields

Unknown fields are rejected with 400 rather than ignored, so a typo in a field name fails loudly instead of silently dropping data.

Response fields

Example request

With media, a specific line, and a scheduled send:

Example response

202 Accepted

Idempotency with external_id

Set external_id on every send. It is your key for two jobs at once: matching messages back to your own records, and making retries safe. How it behaves:
  • The first request with a given external_id creates the message and returns 202 with a new id.
  • Any later request with the same external_id in the same workspace returns the original message body with 200 and the header Idempotent-Replay: true. Nothing is sent twice.
  • Replaying an external_id with a different request body returns 409 idempotency_conflict. Nothing is sent, and the original message is untouched.
  • Keys are held for 30 days from first use. After that, the same value creates a new message.
  • external_id comes back on every webhook for the message, so you can thread replies and delivery events onto your record without storing the BlueReacher id.
Good values are a UUID, or a CRM record id plus the sequence step: crm_88213-step2. Bad values are anything reused across contacts, like the campaign name. Retry 5xx responses, 429, and network timeouts with the exact same body and the same external_id. Use exponential backoff. If the original request landed before the connection dropped, the retry returns the existing message instead of sending a duplicate.

Channel selection and fallback

BlueReacher checks what the recipient can actually receive at send time, then delivers on the best available channel. The channel field sets where that chain starts. imessage is the default and runs the full chain. rcs skips the iMessage attempt and starts at RCS. sms goes straight to SMS. Fallback always continues downward from wherever you start, so channel narrows the options but never locks the message to one path. Things to know about fallback:
  • The decision happens at send time, not when you call the API. For a scheduled message, the channel can differ from the channel value in the response if the recipient’s situation changed in between.
  • The channel in the API response is the intended channel. The message.sent webhook carries the channel that was actually used. Report on the webhook value.
  • Read receipts exist on iMessage. On RCS and SMS you get delivery state only, and SMS delivery depends on what the carrier reports back.
  • Media is re-encoded for the channel it lands on. See Character and media limits.
  • Long messages split into segments on the SMS path. iMessage and RCS send them whole.
  • iMessage sends are unlimited on your line. RCS and SMS fallback traffic is metered per message and shows up on your workspace usage page.
  • The iMessage path has no A2P registration required. SMS fallback travels carrier networks, so carrier rules apply to that traffic. SMS fallback is off by default on new workspaces and your account manager turns it on.
  • To avoid fallback entirely, run the number through the availability check first and only send to iMessage-capable numbers.
If the recipient has opted out, nothing is sent on any channel. STOP keywords are caught automatically and suppressed across your whole workspace, and the request returns 403 recipient_opted_out.

Character and media limits

Text Over 2,000 characters returns 422 content_too_long with the actual count in the error message. On SMS fallback, text is split into standard segments (160 characters GSM-7, 70 characters when the body contains non-GSM characters such as emoji) and billed per segment. Keep cold outreach under 320 characters and the whole thing stays cheap on every channel. Media Supported types: image/jpeg, image/png, image/gif, image/heic, image/webp, video/mp4, video/quicktime, audio/mpeg, audio/mp4, application/pdf. Anything else returns 422 unsupported_media_type. How media is handled:
  • Files are fetched server-side at send time. The URL has to be publicly reachable with no auth header. Signed URLs need to stay valid through the send, which for a scheduled message means valid at scheduled_at, not at request time.
  • content sends first, then attachments in array order, all in the same thread under one message id.
  • On SMS fallback, attachments become MMS. Files over 1 MB are compressed to fit carrier limits. Anything that cannot be compressed under the cap, such as a PDF, is replaced with a secure link in the message body that stays live for 7 days.
  • A URL that returns a non-200, times out, or exceeds the size cap returns 422 media_fetch_failed and nothing is sent. Nothing partially delivers.

Scheduling

Set scheduled_at to a future ISO 8601 timestamp and the message holds in the queue until then. status comes back as scheduled instead of queued.
  • Window: at least 60 seconds and no more than 90 days ahead. Outside that returns 422 invalid_scheduled_at.
  • Include an offset (-05:00) or Z. A timestamp with no timezone is rejected.
  • Scheduled sends respect the sending window on the line. If the time lands inside a quiet window, the message goes out at the start of the next allowed window.
  • Cancel a scheduled message before it fires from the Messages view in the dashboard.
  • The idempotency rules are identical. A retried schedule request with the same external_id returns the existing scheduled message rather than queuing a second one.

Status values

Only scheduled and queued ever come back from this endpoint. Everything after that arrives on your webhook.

Errors

Errors return a single error object:
Retry 429, 500, and 503 with the same external_id. Every 4xx other than 429 fails the same way on retry, so fix the request instead.

Next steps