mapier docs
Messages

Rich links

Send a URL as a preview card, and why you do not control how it looks.

The rich_link payload sends a single URL and asks Messages to render it as a preview card — the tile with a title, an image and a domain, rather than a line of blue text.

{
  "kind": "rich_link",
  "url": "https://example.com/orders/4821"
}

That is the whole payload. kind and url, nothing else — the schema accepts no other keys, and only the URL crosses the wire to the Mac.

URL constraints

Prop

Type

Three things are worth checking before you post:

  • Absolute, with a scheme. https://example.com/orders/4821 works; example.com/orders/4821 and /orders/4821 do not. Only http and https are accepted — no mailto:, tel: or app schemes.
  • 2048 characters, ceiling included. Long tracking parameters get there faster than you expect. Shorten the URL rather than trimming query strings you need.
  • No control characters. Anything below 0x20, plus 0x7f, is rejected. If you are interpolating a URL out of user input, strip whitespace and newlines first.

You do not control the preview

This is the part that surprises people. You send a URL and only a URL. Messages fetches the destination itself and builds the card from what the page publishes — its Open Graph tags, its title, its image. There is no field for a title, a description, a thumbnail or a fallback.

Practically:

  • A destination with good og:title, og:description and og:image tags gets a full card.
  • A destination with none of them gets a thin card, often no more than the domain.
  • A destination behind a login, a paywall or a bot-blocking WAF may render as little more than a URL — Messages is fetching the page as an anonymous client, not as your authenticated user.

If the card matters to you, the work is on the destination page, not in the payload. And test the exact URL you intend to send: a redirect to a different host can produce a different card than the final URL would.

Nothing reports back what the card looked like. A succeeded settlement means iMessage accepted the send, not that a preview rendered — there is no field on the response stream describing the card, and no receipts of any kind.

A worked example

Rich links need a conversation target, like every payload with a kind. A recipient send is plain text only, so it cannot carry one.

curl -X POST $MAPIER_BASE_URL/v1/commands/message.send \
  -H "Authorization: Bearer $MAPIER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4821-receipt-link" \
  -d '{
    "target": {
      "kind": "conversation",
      "conversationId": "a0000000-0000-4000-8000-000000000001"
    },
    "payload": {
      "kind": "rich_link",
      "url": "https://example.com/orders/4821"
    }
  }'

Validating the URL client-side is not optional busywork. The API does not check payload, so a malformed URL returns 202 and settles failed on the stream well after the moment you could have shown the caller an error.

Versus a URL in plain text

You can also put a URL inside an ordinary { text } payload, and it will still be tappable. The difference is the send path: rich_link asks Messages to compose the message as a link, whereas a text payload sends characters and leaves the rendering entirely to the receiving client.

Use rich_link when the link is the message. Use plain text when the URL is one part of a sentence — rich_link has no text field, so you cannot say anything alongside it. If you want both, send two messages.

On this page