Skip to main content
Apple Messages for Business is not a text channel with extras bolted on. Most of what you send is a structured, interactive object that renders natively in the Messages app — a picker, a form, a payment sheet — and returns structured data when the customer interacts with it. Tied supports eight of these. All eight are schema-validated before dispatch, so a malformed message is marked failed in the thread rather than rendering wrong at Apple.

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 two exceptions are Simple Message and Rich Link — one-shot sends with no interaction to display a response for.

The eight primitives

The workhorse. Requires either text or quickReplies (or both).
The quick-reply key gap. The schema requires you to set a key on every quick reply, but Apple’s inbound payload returns only the label text — the key does not come back. So you have to match the reply on its visible label.Practical consequences: keep labels unique within a message, avoid labels that differ only by punctuation or case, and be careful changing label copy — it is effectively your matching identifier. If you need a stable identifier that survives a copy change, use List Picker instead, which does return its own identifiers.
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.
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.
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.
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.
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.
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.