Multipart messages
Text and photos as one message — a caption over a photo, an album, or text and photos interleaved — and why a link that fails sends nothing at all.
A multipart is one message made of several parts — text parts and photo
parts, in the order you list them. The recipient gets one notification and one
message in the thread: a caption above a photo, an album of up to ten photos,
or text and photos interleaved. An iMessage line — live or test — sends one as
a message.send whose payload has kind: "multipart".
{
"kind": "multipart",
"parts": [
{ "kind": "text", "text": "The three we talked about, in the order you asked:" },
{ "kind": "media", "url": "https://example.com/listings/4821/front.jpg" },
{ "kind": "media", "url": "https://example.com/listings/4821/kitchen.jpg" },
{ "kind": "media", "url": "https://example.com/listings/4821/garden.jpg" }
]
}Each photo is a link. Before the message goes out, the platform fetches every link, in order, and hands each file to the line; only then is the message sent. If any one link fails, nothing is sent and the refusal names the part — a partial message is never sent.
Fields
Prop
Type
effect and subject sit beside parts, exactly as they sit beside text
on a plain send. A reply is target.replyToMessageId, as on any send.
Refused before anything is written
Each of these is 422 validation_failed at the field named, and nothing is
queued:
- Fewer than 2 or more than 20 parts, more than 10 media parts, or the same
link twice — at
payload.parts. - A blank text part — at
payload.parts[i].text. - A link that is not
https, cannot be fetched, is too large, or is not a photo, video or PDF — atpayload.parts[i].url. Audio is not a part: iMessage sends an audio file as a message of its own. - A thread the transport has not confirmed — at
target.conversationId, or at the recipient key you wrote, withreason: conversation_not_confirmed.
A multipart to a line on any other channel is 404 unsupported_command with
reason: not_on_channel.
Every link is fetched before anything is sent
The fetch happens inside the request, in the order of the parts, and a link that fails refuses the
whole send at that part's url. So the links have to be reachable from Mapier's servers when you
post — a public https address, not one behind a login or on your own network — and a large album
takes longer to answer than a text does. A 202 means every file reached the line.
Where a multipart can go
A multipart travels on the line's conversation path and nowhere else — the path a thread takes once the transport has confirmed it is a conversation with that one contact, which happens the first time the contact writes into it. See which path a send takes.
Into any other thread it is refused before anything is written, at
target.conversationId or the recipient key with
reason: conversation_not_confirmed. Send the person a text first; once they
answer, the thread is confirmed and the album goes. A group conversation is
refused at target.conversationId too.
What the Mac may still refuse
What the Mac behind the line can send is not known before a multipart is
sent. A Mac whose helper has not announced multipart sends is sent nothing: the
command is accepted with a 202 and then settles failed on the stream with
capability_constraint_violation, failureClass: capability — never several
separate messages in its place. Watch the stream, and fall back to a text and
a rich link rather than retrying unchanged. See
Capabilities.
In test mode the sandbox phone performs a multipart of text parts and draws it as one bubble
holding its text; a multipart holding a photo settles failed with unsupported_capability,
because the sandbox fetches nothing. Live, each part draws as its own bubble and the photos stack
into an album. Test the album against a real handset once, not against the sandbox.
A worked example
An album with a caption, into a conversation the contact opened:
curl -X POST https://api.mapier.ai/v1/commands/message.send \
-H "Authorization: Bearer $MAPIER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: listing-4821-album" \
-d '{
"target": {
"kind": "conversation",
"conversationId": "a0000000-0000-4000-8000-000000000001"
},
"payload": {
"kind": "multipart",
"parts": [
{ "kind": "text", "text": "The three we talked about, in the order you asked:" },
{ "kind": "media", "url": "https://example.com/listings/4821/front.jpg" },
{ "kind": "media", "url": "https://example.com/listings/4821/kitchen.jpg" },
{ "kind": "media", "url": "https://example.com/listings/4821/garden.jpg" }
]
}
}'Checking the bounds client-side saves a round trip; the API checks them again
at payload.parts before it fetches anything.
Related
Attachments and stickers
Receiving the photos people send you, and the relay's upload flow the API does not carry.
Rich links
A URL as a preview card — the other way to put a picture in the thread.
Text and rich text
The effect and subject a multipart takes, as a text does.
POST /v1/commands/message.send
Full field-by-field reference, and what a line carries.