mapier docs

Capabilities

Versioned feature flags each Mac advertises, why a command can be accepted and then fail as unsupported, and how to tell the capability failure codes apart.

Behind your account is a Mac running the connector. When it connects it sends a capability manifest — a versioned list of the operations that build of the connector, on that version of macOS, is able to perform. The service checks every command against that manifest before dispatching it.

You never see the manifest, and you never send capability ids yourself. But it explains a failure mode that otherwise looks arbitrary: a command that works for one account fails for another, with the same request bytes.

Why this exists

Connectors are not deployed in lockstep. Machines run different macOS releases and different connector builds, and Apple removes and reshapes iMessage behaviour between releases — group.leave and participant removal are both casualties on macOS 26. Without negotiation, the service would dispatch an operation an older or newer host cannot carry out and the command would die somewhere unhelpful.

Capabilities move that decision forward. Each flag is versioned (.v1), so a future host can advertise a different contract without breaking clients written against this one.

What each command needs

CommandCapability id
message.send to a DM conversationcommand.message_send.conversation.v1
message.send to a group conversationcommand.message_send.group.v1
message.send to a recipientcommand.message_send.recipient.v1
message.send with any non-text contentcommand.message_send.content.v1
reaction.tapbackcommand.reaction_tapback.v1
reaction.applycommand.reaction_apply.v1
name_photo.sharecommand.name_photo_share.v1
group.createcommand.group_create.v1
group.updatecommand.group_update.v1
group.leavecommand.group_leave.v1

Note that message.send maps to three different capabilities depending on the target. A host can be able to reply into an existing DM while being unable to open a cold thread to a phone number; those are separate flags.

Rich content is additive, not a replacement: a poll sent into a group needs command.message_send.group.v1 and command.message_send.content.v1, with poll present in that capability's supportedKinds array. Plain text needs no content capability at all.

Flags within a capability

Some capabilities carry parameters that narrow what they allow. These are the ones that decide whether a request you can legally construct will actually run:

CapabilityParameterGates
command.message_send.content.v1supportedKindsWhich of rich_text, rich_link, poll, attachment, sticker may be sent
command.reaction_tapback.v1supportsGroupsTapbacks on a group conversation
command.reaction_tapback.v1supportsRemoveremove: true
command.reaction_tapback.v1reactionsThe tapback set the host declares
command.reaction_apply.v1supportsCustomEmojiThe emoji variant of the payload
command.group_update.v1supportsRenameaction: "rename"
command.group_update.v1supportsParticipantsaction: "add_participant" and "remove_participant"
command.group_update.v1supportsPhotoaction: "set_photo"

Twenty-six capability ids exist in total. The rest cover connector-internal concerns — event delivery, history and state reads, media transfer, session control — and operations /v1 does not expose as commands at all, so there is nothing you can address through them from the HTTP API.

There is no discovery endpoint. Nothing on /v1 lets you list the capabilities your connector negotiated, and no field on any response reports them. A client cannot feature-detect. If you need to know whether your account can send polls, remove participants or use custom emoji, contact Mapier and ask — and until then, write the code that handles the failure.

What failure looks like

The capability check happens on the way to the Mac, not at the API boundary. So a command requesting something your host cannot do still returns 202:

202 Accepted
{ "commandId": "cmd-1", "status": "queued", "disposition": "queued" }

and then settles as failed on the response stream with a capability errorCode:

event: command
{
  "commandId": "cmd-1",
  "logicalActionId": "order-8842-confirmation",
  "status": "failed",
  "errorCode": "capability_not_negotiated"
}

Telling the codes apart

capability_not_negotiated — the capability id is absent from the manifest entirely. The host cannot do this operation at all. Retrying is pointless; the identical request will fail identically until the connector is upgraded. Fall back to something the host can do — a plain text message instead of a poll, a tapback instead of a custom-emoji reaction.

capability_constraint_violation — the capability is present, but a parameter in your request falls outside what it declared. A group tapback when supportsGroups is false, remove: true when supportsRemove is false, a rich_link when supportedKinds lists only rich_text, an emoji reaction when supportsCustomEmoji is not set. The operation is supported; this variant of it is not. Change the request, not the timing.

invalid_session_capabilities — the manifest itself was inconsistent, so the session was refused. This is a fault in the connector session rather than in your command. Treat it as transient, back off, and escalate if it persists.

unsupported_capability — the Mac declined the operation at execution time rather than at admission. Handle it the same way as capability_not_negotiated: do not retry unchanged.

None of the four is visible at request time — the 202 looks the same in every case — which is the practical argument for building a fallback path rather than probing. Send the richest form you want, and on a capability failure send the plain-text equivalent; the reader gets the message either way.

On this page