textoptionalstring | string[]Message text. Can be a single string or array of strings (each becomes a separate message)
textoptionalstring | string[]Message text. Can be a single string or array of strings (each becomes a separate message)
/chats/{chatId}/messagesSend a message to a chat. The chatId can be: (1) E.164 phone number, (2) email address, (3) group ID (grp_xxxx), or (4) comma-separated list of phone/email for multi-recipient chats. For multi-recipient, an unnamed group is automatically created or reused if the exact participant combination already exists. For explicit groups, the group must be linked to an existing iMessage chat.
iMessage send-with-effect: set the optional effect field to attach an Apple expressive send (slam, loud, gentle, invisible-ink) or screen effect (echo, spotlight, balloons, confetti, love, lasers, fireworks, celebration). Effects are an iMessage-only feature — when the recipient is on SMS/RCS the message is delivered without the animation. Effects are not supported in multipart (parts) mode.
Threaded replies (iMessage inline reply): set the optional reply_to field to send the outgoing message as a reply to a specific earlier message. Two shapes are accepted: { "message_id": "msg_…" } references a Blooio-minted message in the same chat (most common — the message_id returned by an earlier send or surfaced on a message.received webhook), or { "guid": "…", "part_index": 0 } references the raw iMessage GUID for the rare case where the parent wasn't recorded by Blooio. The reply must target the same chat and the same from-number as the new send, and the parent must be no older than 30 days (the iMessage on-device retention horizon). Reply support is iMessage-only and is rejected on Twilio, dashboard-Twilio, and hybrid send paths; it's also rejected on multi-message fan-outs (text array or per-part URL-balloon batch). See the 400 responses for the full set of reply_target_* error codes.
chatIdRequiredstringChat identifier. Can be: (1) phone number in E.164 format (e.g., +15551234567), (2) email address, (3) group ID (grp_xxxx), or (4) comma-separated list of phone numbers/emails for multi-recipient group chats (e.g., +15551234567,+15559876543). All values should be URL-encoded.
AuthorizationRequiredstringYour API key, sent as a bearer token: Authorization: Bearer <api_key>. Editing this stays in sync with the API key box on the right.
Idempotency-KeyoptionalstringUnique key to prevent duplicate message sends. If the same key is used again, the original message_id and status are returned.
textoptionalstring | string[]Message text. Can be a single string or array of strings (each becomes a separate message)
formatoptionalstringHow to interpret text (and each parts[].text). Defaults to plain, which sends the string exactly as given.
With markdown, four constructs are parsed and delivered as real iMessage rich text — the recipient sees styled text, not delimiters:
| Construct | Syntax |
| --- | --- |
| Bold | **bold** or __bold__ |
| Italic | *italic* or _italic_ |
| Underline | ++underline++ |
| Strikethrough | ~~strike~~ |
They nest freely (**bold and _italic_**). Everything else Markdown can express — headings, lists, links, code spans, blockquotes, images — is NOT styling iMessage can carry, so it is passed through as literal characters: [Blooio](https://blooio.com) is delivered with its brackets and URL intact, and # Heading keeps its #. Escape a delimiter with a backslash (\*not italic\*) to send it literally.
The styling travels in the message's attributed body, so the stored text and the text returned on reads and webhooks is always the plain string the recipient sees, with the delimiters removed. The Markdown itself comes back as formatted_text, re-serialized into a normalized spelling rather than echoed verbatim (__bold__ returns as **bold**).
Only valid on Blooio iMessage channels — 400 format_unsupported_for_channel_type on any other channel type, since no other channel type has a rich-text equivalent and would otherwise deliver your delimiters as literal text. Rich text also requires the message to be delivered over iMessage: a Blooio send that falls back to SMS arrives as unstyled plain text (the text string), because SMS cannot carry styling.
Applies to a text send and to parts. Rejected with 400 invalid_content when combined with attachments — a media caption is not a styled bubble, so send the media and the styled text as two messages — when set without text or parts, when the Markdown source exceeds 20000 characters, or when it compiles to more than 256 distinct formatting ranges.
"plain""markdown"attachmentsoptionalstring | object[]Array of attachment URLs or objects with url/name.
**Voice memos:** a single audio file (.mp3, .m4a, .wav, .aac, .opus, .ogg) is automatically sent as a voice memo (the native waveform/scrubber bubble), not a plain audio-file attachment — no extra field is needed. A voice memo is a standalone bubble, so it cannot be combined with text or any other attachment; send the voice memo and the text as two separate messages.
Array of string | object
urlRequiredstringnameoptionalstringuse_typing_indicatoroptionalbooleanWhether to show typing indicator before sending. Defaults to org preference.
from_numberoptionalstringE.164 phone number to send from. For Twilio API keys, this is optional — if omitted, the first assigned Twilio number is auto-selected. For Blooio (iMessage) API keys, this selects a specific number from your pool. Must be a number assigned to your API key.
partsoptionalobject[]Ordered array of message parts. Two modes:
1. **Multipart mode** — parts sent as a single unified iMessage bubble (mix of text and attachment parts). This is the default.
2. **URL-balloon batch mode** — triggered when any part has a link_preview object. Each part becomes its own rich-link-preview iMessage; parts are sent sequentially in array order. In batch mode every part must be text-only with text being a single http(s) URL. Response contains message_ids[] + count instead of message_id.
Array of object
textoptionalstringText content for this part. Mutually exclusive with 'url'.
mentionoptionalstringParticipant phone number or email to @-mention. Only valid with 'text'. The entire text of the part is rendered as the mention.
urloptionalstringURL to an attachment for this part. Mutually exclusive with 'text'.
nameoptionalstringFilename for the attachment. Only valid with 'url'.
link_previewoptionalLinkPreviewOptional. Per-part rich-link-preview override. When any part carries this, every part must be a text-only single-URL part (URL-balloon batch mode).
image_urloptionalstringHTTPS URL to an image (png, jpg, webp, gif). Blooio downloads the image server-side and attaches it as the rich-link hero. Max 16 MB. If the download fails or returns a non-image MIME, the send falls back to auto-fetched OG metadata.
titleoptionalstringBold title line rendered in the iMessage bubble. Overrides the page's <meta property="og:title">.
link_previewoptionalLinkPreviewOptional. Override the rich-link-preview image and/or title on URL messages. See the LinkPreview schema. When omitted, Blooio auto-generates the preview from the page's Open Graph tags.
image_urloptionalstringHTTPS URL to an image (png, jpg, webp, gif). Blooio downloads the image server-side and attaches it as the rich-link hero. Max 16 MB. If the download fails or returns a non-image MIME, the send falls back to auto-fetched OG metadata.
titleoptionalstringBold title line rendered in the iMessage bubble. Overrides the page's <meta property="og:title">.
effectoptionalstringOptional. Attach an iMessage send-with-effect to the outgoing message.
**Bubble effects** (apply to a single text bubble):
- slam — Slam
- loud — Loud
- gentle — Gentle
- invisible-ink — Invisible Ink
**Screen effects** (full-screen animation in the recipient's chat):
- echo — Echo
- spotlight — Spotlight
- balloons — Balloons
- confetti — Confetti
- love — Love (heart)
- lasers — Lasers
- fireworks — Fireworks
- celebration — Celebration (sparkles)
Values are case-insensitive and accept either dashes or spaces ("Invisible Ink" and "invisible-ink" both work). Pass "none" or omit the field to send without an effect.
**Limitations:**
- iMessage-only — when the chat is delivered as SMS or RCS the message is sent without an animation.
- Not supported alongside the parts array (multipart bubbles cannot carry an effect). Use the top-level text field instead.
- When text is an array, every message in the array is sent with the same effect.
"slam""loud""gentle""invisible-ink""echo""spotlight""balloons""confetti""love""lasers""fireworks""celebration""none"reply_tooptionalReplyToRequestOptional. Send this message as an iMessage inline reply targeting a specific earlier message. iMessage-only — rejected on Twilio, hybrid, and multi-message fan-outs (text array or URL-balloon batch).
message_idoptionalstringBlooio message_id of the parent. Must belong to the same chat, same from-number, and be no older than 30 days. Returns 404 reply_target_not_found if unknown.
guidoptionalstringRaw iMessage GUID of the parent. When supplied without a message_id, Blooio attempts to look up the parent via provider_message_guid; if the parent isn't in our table the send still proceeds (Lava will thread on the device when possible) and the response carries parent_unresolved: true.
part_indexoptionalintegerWhich part of the parent to reply to. Defaults to 0 (covers the 99% case of replying to a single-part text message).
message_idoptionalstringID of the sent message (single-message sends)
message_idsoptionalstring[]IDs of sent messages. Present when text is an array or when parts uses per-part link_preview (URL-balloon batch mode).
countoptionalintegerNumber of messages sent. Only present in URL-balloon batch mode.
statusoptionalstringInitial status of the message(s). queued = accepted for delivery (the normal 202 result); failed = rejected before dispatch. Subsequent transitions (sent → delivered, or failed) are reported via the status endpoint and message.status webhooks.
"queued""failed"group_idoptionalstringGroup ID when sending to multi-recipient (new or existing)
group_createdoptionalbooleanTrue if a new unnamed group was created for this multi-recipient message
participantsoptionalstring[]List of participants (present for multi-recipient)
parent_unresolvedoptionalbooleanPresent (and true) only when reply_to.guid was supplied without a message_id and the GUID didn't map to any Blooio-minted row. The send still proceeds and the device may still thread it; this flag signals that Blooio couldn't link the new message to a known parent.
Sends a live request with your values and shows the real response below. Your key is stored only in this browser.
curl -X POST https://api.blooio.com/v2/api/chats/chat_a1b2c3d4/messages \{ "message_id": "msg_a1b2c3d4", "message_ids": [ "string" ], "count": 3, "status": "queued", "group_id": "grp_a1b2c3d4", "group_created": false, "participants": [ "string" ], "parent_unresolved": false}