There are two kinds of line. Flow’s shared line is free to try: your first sign-in at flow.engineer opens it to your account, and people reach your app by texting its join message. A dedicated line is your own number, set up with the Flow team; only dedicated lines take group chats, call forwarding and, on request, writing first. Lines reply after the person writes, unless writing first is switched on for a dedicated line.
TypeScript
1. Get a line
- A dedicated line
imessage (set by the Flow team): fallback (the SMS/RCS add-on, section 6), call_forwarding (section 8) and can_initiate (writing first, section 5).
2. Bubbles fit iMessage
People read iMessage as short lines.reply() uses shorter bubbles here (about 400 characters before it cuts at a sentence end) than on Telegram. See Streaming replies.
3. Tapbacks and effects
- Reactions (
POST .../reaction): ❤️ 👍 👎 😂 ‼️ ❓ show as tapbacks, and any other emoji as an emoji reaction. Groups take none (422 unsupported_content,channel_codegroup_unsupported). - Effects (
POST .../effect) send text with an iMessage effect:
TypeScript
slam, loud, gentle, invisible_ink, echo, spotlight, balloons, confetti, love, lasers, fireworks and celebration. Which ones a contact’s device shows may vary, and a message that goes by SMS or RCS shows the text without the effect. Effects work on iMessage only: send the same text as a basic message on other channels.
4. No buttons: list the choices in the text
iMessage has no buttons, lists or carousels: they answer422 unsupported_content with param kind, and nothing is sent. Flow converts nothing, so send a basic message whose text lists the choices, and read the person’s answer, which arrives in words as a basic message.
TypeScript
buttons on every channel, catch the 422 and send the text instead with a new Idempotency-Key: a 422 is kept under its key, so add what the substitute is, such as evt_123:time:basic. See unsupported_content.
5. Who writes first
iMessage lines are personal-style numbers, and iMessage watches closely for unwanted messages. Flow protects your line:- The person writes first. A line replies only, unless writing first is switched on for it (
imessage.can_initiate). From a reply-only line, starting a conversation with a new contact (POST /v0/messages) is refused with403 permission. Someone who has written to the line before is an open conversation, and replies to them are not budgeted. - Writing first is available on request, for dedicated lines only. The Flow team switches it on per line, within a warm-up: the line’s new-contact budget (
limits) starts small and grows. If the channel still refuses a start, the send ends inmessage.failedwithoutside_window. The shared line never writes first. - Get people to write with the opt-in link. When the line has one, the sender’s
address.linkopens Messages with the line and a prefilled text the person sends to start. Put it on your site, receipts or a QR code. - No cold outreach. Sending the same text to many people, or messages that get no reply, can throttle the line (
sender_throttled).
6. SMS and RCS from the same number
With the SMS/RCS add-on (imessage.fallback on the sender), a message to someone who cannot get iMessage goes by SMS or RCS from the same number. It is included on Flow’s shared line, and is an add-on for a dedicated line, arranged with the Flow team. Without it, a message to someone not on iMessage fails (message.failed).
Your app never picks the network: it is chosen per message when it is sent. Message.network says which way a message went: imessage, sms or rcs. It is set on inbound messages, and on yours once the channel reports it (data.message.network in message.delivered or message.failed).
The network is chosen after Flow sends, so Flow sends every message as for iMessage: a message that goes by SMS or RCS shows no imessage.styles, no imessage.subject and no effect. Message.network tells which way it went. Keep text readable without them when the add-on is on. Edits and unsends of a message that went by SMS or RCS are refused with 422 unsupported_content, channel_code not_on_sms: send a new message instead.
7. Group chats
Only dedicated lines take group chats, and only ones people add the line to. Flow’s shared line ignores group chats: they never reach your app from it.- A group is one conversation with
typegroup. It has nocontact;groupholds the group’sname, when it has one, and itsparticipants(each a contact on the channel, made the first time Flow sees them). Every inbound message carriesfrom, the contact who wrote it. - People who join or leave change the list without an event. Read the conversation (
GET /v0/conversations/{conversation_id}) for the current list; events inline onlygroup_name. - Writers count toward your plan’s people; members who never write do not. A writer past a limit is held: their messages wait and arrive when they are let in, and the rest of the group’s messages are not held up. See Pricing.
- Reply with the normal sends (
POST /v0/conversations/{conversation_id}/basicand the other kinds’ endpoints): basic messages (withimessage.styles,imessage.subjectandlink_preview), media, voice notes, effects, threaded replies (reply_to), edits and unsends work in groups. - No reactions, typing or read receipts from your line. Each answers
422 unsupported_contentwithparamkindandchannel_codegroup_unsupported, and nothing is sent: leave them out in groups. - Flow cannot create a group, rename one, or add or remove people. A start (
POST /v0/messages) always makes a direct conversation.
POST /v0/test/conversations with "channel": "imessage" and a group (name, participants) makes a simulated group conversation under the same rules. See Test and live mode.
8. Calls
- Phone calls to a dedicated line’s number can be forwarded to a phone you choose, set up with the Flow team with the SMS/RCS add-on (
imessage.call_forwarding.phoneshows where). Forwarded calls send no event. The shared line does not forward calls. - FaceTime calls are never forwarded: the line cannot answer them, and each attempt arrives as a
call.receivedevent (data.call.contact,data.call.networkfacetime) in the direct conversation with the caller, made if it is new. A webhook endpoint receives it only when it listscall.receivedinevents. - A call is not a message: it does not count toward your plan’s people, and it does not let a reply-only line write to the caller first.
9. Text styles, subjects and link previews
text is sent exactly as written: Flow reads no markdown, and text that looks like markup shows as written. Style a basic message with imessage.styles, ranges of the text (start and length in UTF-16 code units) with a style: bold, italic, underline, strikethrough, big, small, or the animations shake, nod, explode, ripple, bloom and jitter. imessage.subject (up to 200 characters) shows as the message’s bold subject line, and link_preview: false sends links without a rich preview.
TypeScript
imessage block works on iMessage only: on another channel it answers 422 unsupported_content with param imessage. See Send a basic message.
10. What iMessage supports
Each endpoint’s page opens with the channels it works on and their limits.
11. Contacts
An iMessage contact’saddress.handle is a phone number or an email address. Do not assume a phone number. Reply into the conversation the person started rather than addressing them by handle.
Related
- Going live: live keys and iMessage lines.
- Pricing: plans and how many people each reaches.
- Content types