The envelope six of them share
Six primitives wrap their payload in the same two-part envelope. Understanding it once explains most of the channel:required
What the customer sees in the thread before they interact — a title, subtitle and optional image.
This is the bubble sitting in their Messages app.
required
What the bubble becomes after they respond. The picker collapses into a confirmation showing what
they chose.
required
The actual payload —
listPicker, timePicker, form, pay, oAuth or imessageExtension.Why this matters: the thread has to read sensibly after the interaction is over. A customer
scrolling back three weeks later should see “Appointment confirmed — Tuesday 3pm”, not an inert
picker they can no longer use.
responseDisplay is what makes that happen, and it is required, not
optional.The eight primitives
Simple Message — text, quick replies and attachments
Simple Message — text, quick replies and attachments
The workhorse. Requires either
text or quickReplies (or both).Rich Link — a card with an image or video
Rich Link — a card with an image or video
The only primitive that takes video as well as an image. Requires just
richLink — no envelope,
because there is nothing to respond to.Use it for a product, an article, an order confirmation — anything where a tappable card beats a
bare URL. It renders as a proper preview card rather than a link.List Picker — choose one or more from a list
List Picker — choose one or more from a list
A native list the customer scrolls and taps. Supports sections, per-item images and multi-select.This is the only primitive with dependable identifiers on the way back. If your flow needs to
branch on exactly what the customer picked, and needs that branch to survive a copy change, use a
List Picker rather than quick replies.Media slots:
sendDisplay.image, responseDisplay.image, and a per-item image.Time Picker — pick an appointment slot
Time Picker — pick an appointment slot
Presents timeslots natively; the customer picks one without leaving Messages. The reply comes back
as a structured selection, so booking flows do not have to parse free text like “tuesday afternoon
works”.Media slots:
sendDisplay.image, responseDisplay.image, and a third slot on the primitive
itself, timePicker.image.Form — a multi-page guided flow
Form — a multi-page guided flow
The largest schema of the eight, and the most capable. A multi-page sequence with a splash screen,
typed inputs, select pages and picker pages — collected inside Messages, returned as structured data.Use it where a web form would otherwise break the thread: returns intake, warranty registration,
onboarding questionnaires.Media slots:
sendDisplay.image, responseDisplay.image, splash.image, and per-item image on
select and picker pages.Apple Pay — take payment in the thread
Apple Pay — take payment in the thread
A native payment sheet. The customer authenticates with Face ID or Touch ID and pays without leaving
the conversation — no redirect, no checkout page, no re-entering card details.This is the single most commercially significant primitive on the channel. It also has a billing
consequence worth knowing: a resolution where the agent takes a payment is a
write_financial, and
because the processor holds the card number and Tied acts against a token, it does not derive
compliance_gated. See Resolution pricing.Media slots: sendDisplay.image, responseDisplay.image.OAuth — authenticate the customer
OAuth — authenticate the customer
Runs an OAuth flow inside the thread, so you know who you are talking to before doing anything
sensitive. The customer signs in with your identity provider and control returns to the conversation.This is what turns an anonymous thread into an authenticated session — the precondition for account
changes, order lookups against a real identity, and anything you would not do for a stranger.Media slots:
sendDisplay.image, responseDisplay.image.iMessage Extension — your own app surface in the thread
iMessage Extension — your own app surface in the thread
Embeds a custom iMessage app inside the conversation. The most powerful and the most work: it needs a
companion iOS app extension you build and ship.Reach for it when none of the other seven fit — a seat picker, a configurator, a map-based selector.Media slots:
sendDisplay.image, responseDisplay.image. Unlike the others, it also carries a
required icon URI on the primitive itself.Every primitive is validated before it sends
All eight are checked against their JSON Schema before dispatch — at send time, and again at flow-dispatch time. A message missing a required field, or carrying an unexpected one, does not reach Apple: it is accepted into the thread and then marked failed, rather than rendering wrong on the customer’s phone. That is deliberate: Apple’s own failure modes are opaque, and a message that silently does not render is far harder to debug than one that fails visibly with a reason.All eight primitives set
additionalProperties: false — at the top level and on every nested
object. Simple Message alone sets it four separate times, once per nested shape in its schema.
Fields Apple does not recognise are not passed through anywhere in any primitive — they are a
validation error. If you are porting content from another platform, expect to map fields
explicitly rather than pass a superset and hope.Choosing between them
Next
Known limitations
The constraints worth knowing before you design a flow around these.
Channel-native flow nodes
Emitting these primitives from inside a chatbot flow.
Entry points
The eight ways a customer can start the conversation in the first place.
Apple Messages fees
What delivery costs. Apple Messages for Business has no agent fees.