message.send
Send text, rich text, a link preview, a poll, an attachment or a sticker.
POST /v1/commands/message.sendSends a message. The payload is a union discriminated by kind; plain text
omits kind entirely.
Target
Accepts a conversation target (reply into an existing thread) or a recipient target (start a new one).
Prop
Type
A recipient target sends plain text only, and it fails quietly rather than
loudly. The endpoint forwards payload.text and discards every other key
— so a recipient send carrying kind: "rich_text" and an effect returns
202 and delivers the bare text, with the effect silently dropped. You only
get a 400 when recipientExternalId or text is missing entirely.
To send rich content to someone new: send plain text first, wait for the conversation to appear on the stream, then send into it with a conversation target.
Routing path: a conversation target uses the agent-turn path and honours
Idempotency-Key. A recipient target uses the admin path and does not.
Payload
Text
The default. No kind field.
Prop
Type
{ "text": "hello" }rich_text
Text plus reply threading, a screen effect, or a subject line.
Prop
Type
{
"kind": "rich_text",
"text": "Congratulations",
"effect": "confetti",
"replyToMessageExternalId": "guid-1"
}rich_link
Sends a URL that iMessage renders as a link preview.
Prop
Type
{ "kind": "rich_link", "url": "https://example.com/launch" }poll
Prop
Type
{
"kind": "poll",
"question": "Lunch?",
"options": ["Tacos", "Ramen", "Salad"]
}Reading votes back is covered in Polls.
attachment
Prop
Type
transferId refers to media already staged in Mapier's storage, and the /v1 API has no
endpoint that produces one. Until an upload endpoint ships, this payload cannot be used. Inbound
attachments can still be downloaded.
sticker
Prop
Type
Same limitation as attachment.
Request
curl $MAPIER_BASE_URL/v1/commands/message.send \
-H "Authorization: Bearer $MAPIER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2481-shipped" \
-d '{
"target": {
"kind": "conversation",
"conversationId": "a0000000-0000-4000-8000-000000000001"
},
"payload": { "text": "Your order shipped." }
}'Starting a new conversation instead:
{
"target": { "kind": "recipient", "recipientExternalId": "+14155550100" },
"payload": { "text": "hi" }
}Response
{
"commandId": "cmd-1",
"status": "queued",
"disposition": "queued"
}Then, on the response stream:
{
"commandId": "cmd-1",
"logicalActionId": "order-2481-shipped",
"status": "succeeded",
"errorCode": null
}{
"commandId": "cmd-1",
"logicalActionId": "order-2481-shipped",
"status": "failed",
"errorCode": "stale_target"
}Errors
| Status | Code | Cause |
|---|---|---|
400 | recipient_send_requires_recipientExternalId_and_text | Recipient target missing recipientExternalId or text |
400 | invalid_conversationId | conversationId is not a UUID |
404 | conversation_not_found | Unknown conversation, or another account's |
422 | (varies) | Recipient address failed validation |
503 | no_live_connector | No Mac available |
Settlement codes you will see for this command: stale_target (reply target
aged out), invalid_target, gateway_rejected, send_returned_not_ok,
accepted_echo_unconfirmed. See Error codes.
Capabilities
Requires command.message_send.conversation.v1, .group.v1 or .recipient.v1
depending on the target. Rich kinds additionally require
command.message_send.content.v1 with the kind listed in its supportedKinds.
See Capabilities.