Developer guideiMessage API7 min read
iMessage tapbacks, typing indicators and effects via API
How to send iMessage tapbacks, typing indicators, read receipts, effects, edits and unsends from Flow, with the limits that apply.

The short answer
The details that make an agent feel like iMessage are tapbacks, typing, read receipts and effects. Through an API they work with limits: a fixed tapback set, typing only soon after the person's last message, edits for 15 minutes and unsend for two. Keep a plain-text fallback on.
Building on the iMessage API? Build on iMessage with Flow: one agent for iMessage, WhatsApp and Telegram. New to it? Read the iMessage API guide.
What an API can send
The things that make an iMessage conversation feel native are small: a typing bubble, a thumbs-up on a message, confetti on an order confirmation. A good iMessage API exposes them, and a good agent uses them sparingly.
Flow’s iMessage features cover what the line supports: text up to 9,999 characters, photos, video and audio, documents, voice notes, tapbacks, typing, read receipts and effects. There are no buttons, lists or templates. If you design an iMessage agent, these are the details that matter.
Tapbacks
Reactions become tapbacks. iMessage has a fixed set, so Flow maps what you send to the closest one. This example reacts and then replies:
for await (const event of flow.events.stream({ types: ["message.received"] })) {
const text = contentText(event.data.message.content);
await event.conversation.react(event.data.message.id, "👍"); // shows as the Like tapback
await event.conversation.reply(await askMyAgent(text));
}
With fallback: "auto", which react() sets, Flow uses the closest tapback or skips the reaction and says so in delivered_as. Keep the fallback on because the exact set of reactions a line can send may vary.
Use a tapback to say “got it” while the agent works, not as decoration on every message.
Typing and read receipts
Show typing while the model works. On Flow:
- Typing shows for up to 60 seconds, and works within five minutes of the contact’s last message. Outside that, the call answers
409 outside_window, and you can ignore it. - Channels clear the indicator after a few seconds, so keep turning it on until you send.
reply()does this for you: it turns typing on, sends bubbles as they are ready and turns it off, even if the stream fails.
Read receipts work for the whole conversation. iMessage has no per-message receipt, so up_to has no effect. Mark the conversation read when your agent starts work, which is what a person would do.
On Flow, typing indicators are iMessage-only, need an existing conversation and are best-effort. They work within five minutes of the person’s last message.
Effects
Effects send text with an iMessage bubble or screen effect:
import { effect } from "@flow-engineer/messaging";
await event.conversation.send({ content: effect("Your order is confirmed!", "confetti"), fallback: "auto" });
Flow lists these effects: slam, loud, gentle, invisible_ink, echo, spotlight, balloons, confetti, love, lasers, fireworks, shooting_star and celebration. Which ones a line can send may vary, so keep fallback: "auto", which sends plain text instead.
An effect is a moment, not a style. Use one for a confirmation, a birthday or a small win, and the rest of the time send plain text.
Edit and unsend
On Flow’s iMessage line:
- Edit. You can replace the text of a sent message within 15 minutes, but not the message that started the conversation.
- Unsend. You can remove a message within two minutes.
WhatsApp supports neither, so write the agent so a mistake can be corrected with a new message, not only with an edit. The one-agent guide has the table of what each channel can do.
Build expressive replies with Flow
Flow exposes reactions, typing, effects, edits and unsend through the same conversation API. Use the documented fallback behavior so your agent remains useful when a particular effect is unavailable.
Frequently asked questions
Can I send iMessage tapbacks through an API?
Yes. On Flow a reaction becomes a tapback. iMessage has a fixed set, so with fallback set to auto Flow uses the closest tapback, or skips the reaction and says so in the delivered_as field.
Can an API show the typing indicator?
Yes. On Flow it works within five minutes of the contact's last message. Outside that, the call answers 409 outside_window and is safe to ignore. Channels clear the indicator after a few seconds, so keep turning it on while your agent works.
Do read receipts work per message?
No. On Flow, iMessage has no per-message read receipt, so the whole conversation is marked read and the up_to value has no effect.
Which iMessage effects can I send?
Flow lists slam, loud, gentle, invisible ink, echo, spotlight, balloons, confetti, love, lasers, fireworks, shooting star and celebration. Which ones a line can send may vary, so keep a plain-text fallback on.
Can I edit or unsend an iMessage from code?
On Flow you can edit within 15 minutes of sending, but not the message that started the conversation, and unsend within two minutes. WhatsApp does not support either.
Keep reading
All posts: the Flow blog. The Flow docs have the reference.
From reading to building
Your agent, on iMessage and everywhere else.
Flow gives your agent an iMessage line, and the same code answers on WhatsApp and Telegram and works as an MCP server and CLI. See how it works on iMessage.
Build on iMessage with Flow