Conversation lifecycle
How an Apple Messages for Business conversation flows end to end — inbound-first threading, typing indicators, read receipts, bot-to-human handoff, and closing — all through the Blooio v4 chats API.
An Apple Messages for Business conversation has a shape: a customer opens it, you (an automation, a human agent, or both) work it, and eventually it closes. This page walks that lifecycle and the chat controls that go with it — typing indicators, read receipts, handoff between automation and humans, and closing.
Everything here hangs off a chat. The inbound message.received webhook that opens a conversation carries a chat_id; use it with the chats endpoints for the rest of the conversation.
A conversation handled by automation first, then escalated to a human agent and resolved. Click a step for details.
The lifecycle
- Open. The customer taps a Messages entry point (or accepts an invitation). Apple mints an opaque id for them and Blooio delivers
message.receivedwith thechat_idand the opaque id as the sender. - Reply. You answer by addressing the opaque id, or by posting to the chat directly with
POST /v4/chats/{chatId}/messages(the sender and recipient are fixed by the chat, so omitfrom/to). - Work the thread. Show typing, mark it read, send interactive messages, take payment, or hand off to a human.
- Close. The conversation ends — resolved by you, or left by the customer. See Closing & opt-out.
The opaque id is stable for that customer and your brand, so a returning customer threads back into the same conversation history.
Typing indicators
Show a typing indicator before a reply so a pause reads as "thinking" rather than a stall. Start it with POST /v4/chats/{chatId}/typing:
curl -X POST https://api.blooio.com/v4/chats/chat_.../typing \
-H "Authorization: Bearer bl_live_..." \
-H "Content-Type: application/json" \
-d '{ "state": "started" }'Try itClear it by sending { "state": "stopped" }, or with DELETE /v4/chats/{chatId}/typing. You don't have to clear it manually: Apple auto-expires a typing indicator 60 seconds after it starts if you never send a message or a stop. A good rhythm is about one second of typing before each message you send — see the timeouts in Capabilities & limits.
When the customer is typing to you, Blooio delivers typing.started / typing.stopped webhook events so your agent console can show the same.
Read receipts
Mark a conversation read when your agent (or bot) has seen it, with POST /v4/chats/{chatId}/read:
curl -X POST https://api.blooio.com/v4/chats/chat_.../read \
-H "Authorization: Bearer bl_live_..."Try itHandoff: automation ↔ human
Most desks run a bot for the first touch and bring in a human when the question needs one. Blooio emits handoff webhook events so your systems can coordinate who owns the conversation:
| Event | Fired when |
|---|---|
handoff.created |
A conversation is handed off (for example, a bot escalates to a human queue). |
handoff.customer_reply |
The customer replies while a handoff is pending. |
handoff.acknowledged |
An agent (or system) picks up the handoff. |
handoff.resolved |
The handoff is closed out. |
Subscribe to these alongside message.received to drive routing: when handoff.created fires, surface the thread in your agent console; when a human replies, send through the same chat so the customer sees one continuous conversation. Replies from automation and from humans both go out over POST /v4/chats/{chatId}/messages — the channel is the same; only your internal routing changes.
Note A customer can ask your automation to stop. Honor it: once a customer has opted out of automated messages, route the conversation to a human and don't resume bot sends until they re-engage.
Closing & opt-out
A chat is normally open. It becomes closed when the conversation ends — including when the customer leaves or reports the conversation (Apple's CloseSession). Blooio surfaces this as a chat.closed webhook event; for a conversation that began as an invitation, the close carries your original reference_id.
- Sending to a closed chat is rejected with a conflict such as
409 chat_closed— don't retry; wait for the customer to re-engage. - Mark a thread closed from your side with
PATCH /v4/chats/{chatId}when your product considers it resolved. - Respect opt-out. If a customer leaves or reports a conversation that started from an invitation, do not invite that number again until they opt back in. See Business invitations.