Skip to content
Linq Copy agent prompt
Messaging

Stickers

Peel an emoji or image onto a message, send a sticker of its own, place one inside text, and reposition it.

A sticker is an image or emoji stuck to a conversation rather than sent as a photo. You control its position, size and orientation.

Stickers are an iMessage feature. See Protocol Selection for what each protocol supports.

What the recipient sees Endpoint
Peel onto a message an emoji or image stuck to an existing bubble, positionable POST /v3/messages/{messageId}/reactions with type: "sticker"
Send it as a message a sticker in the conversation, no bubble, peelable by the recipient onto anything POST /v3/chats/{chatId}/messages with a media part carrying sticker: true
Place it inline in text sticker images in the line with the words, in place of the characters they cover POST /v3/chats/{chatId}/messages with inline_stickers on a text part

Placement applies only to a peel. A sticker sent as its own message isn’t attached to anything, and an inline sticker is positioned by the character range it replaces.

Pass type: "sticker" with what to peel — an emoji, or an image you’ve uploaded:

Terminal window
curl -X POST https://api.linqapp.com/api/partner/v3/messages/{messageId}/reactions \
-H "Authorization: Bearer $LINQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operation": "add",
"type": "sticker",
"emoji": "🎉"
}'
Field Required Type Description
operation Yes add | remove Whether to add or remove the reaction
type Yes object
custom_emoji No string Custom emoji string. Required when type is "custom". This is a **tapback** — the emoji sits in the tapback bubble on the corner of the message. To peel an emoji onto the message as a draggable sticker instead, use type "sticker" with `emoji`.
emoji No string A single emoji to peel onto the message as a sticker. Only valid when type is "sticker". Exactly one of `emoji`, `url` or `attachment_id` is required when type is "sticker". Not to be confused with `custom_emoji`, which produces a tapback.
url No string (uri) Linq attachment URL of the sticker image — the `download_url` returned by `POST /v3/attachments`. Only valid when type is "sticker". The image must already be stored with us. To send a sticker from elsewhere, upload it with `POST /v3/attachments` first and pass `attachment_id`. Exactly one of `emoji`, `url` or `attachment_id` is required when type is "sticker".
attachment_id No string (uuid) Reference to a sticker image pre-uploaded via `POST /v3/attachments`. Only valid when type is "sticker". Exactly one of `emoji`, `url` or `attachment_id` is required when type is "sticker".
part_index No integer Optional index of the message part to react to. If not provided, reacts to the entire message (part 0).
placement No object

Pick one of emoji, url or attachment_id.

Field What it takes Pre-upload needed
emoji a single emoji No
attachment_id an image from POST /v3/attachments Yes
url the download_url from that same upload Yes

attachment_id and url are two ways of naming the same stored image, so use whichever you have on hand.

Animated images work. A GIF peels onto the bubble and plays there, in whatever shape the file already has.

url takes a Linq attachment address only — upload the image first.

Terminal window
curl -X POST https://api.linqapp.com/api/partner/v3/messages/{messageId}/reactions \
-H "Authorization: Bearer $LINQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operation": "add",
"type": "sticker",
"attachment_id": "550e8400-e29b-41d4-a716-446655440000"
}'

A message can hold several parts — text, an image, a link. part_index picks which one the sticker lands on, counting from 0. Omit it and the sticker goes on the first. It works the same way for a tapback.

Both take an emoji and they look nothing alike:

What you get
type: "sticker" + emoji the emoji peeled onto the bubble — draggable, resizable, rotatable
type: "custom" + custom_emoji a tapback in the small bubble at the message’s corner

For images, the attachments API doubles as your sticker library: upload once, then peel the same attachment_id as often as you like. A sticker you send repeatedly — a logo, a mascot, a seasonal set — should be uploaded once and referenced by id, not re-uploaded on every send. (Emoji need none of this; there’s nothing to store.)

One caveat on tiers — a sticker meant for reuse belongs on the persistent tier, which is the default. Attachments on the ephemeral tier are removed within roughly 24–48 hours of upload, taking the sticker with them.

placement sets where the sticker lands on the target bubble. Every field is optional — omit the object entirely for the native-looking default: centred, unrotated, at the size that source gets natively.

Field Required Type Description
x No number (double) Horizontal position on the target bubble, from -1 (far left) to 1 (far right). 0 is centred.
y No number (double) Vertical position on the target bubble, from -1 (top) to 1 (bottom). 0 is centred.
scale No number (double) How large the sticker is drawn. Omit it for the default size — equivalent to `1` for an image, or `0.5` for an emoji. Values outside 0.05–2.5 are clamped rather than rejected. Scale is linear, so 2.5 is a little over six times the area.
rotation No number (double) Clockwise rotation in degrees.

The default size depends on what you peeled: an emoji lands smaller than an image, so scale: 1 is not the same size for both. Out-of-range values clamp rather than reject, so a size or angle never fails a send.

PATCH /v3/messages/{messageId}/reactions/{reactionId}

Repositioning reaches every device in the conversation, exactly as dragging the sticker by hand would. Omitted fields keep their current value.

Terminal window
curl -X PATCH https://api.linqapp.com/api/partner/v3/messages/{messageId}/reactions/{reactionId} \
-H "Authorization: Bearer $LINQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"placement": {
"x": 0.6,
"y": 0.5,
"scale": 0.75
}
}'

reactionId is the id on the reaction as it appears on the message, or reaction_id on the reaction.added webhook. Stickers stack, so the target message alone can’t identify one — this id is the only thing that distinguishes one sticker from another on the same bubble.

Only stickers can be repositioned. A tapback has no placement, so a non-sticker reactionId is rejected.

Set sticker: true on a media part. The image arrives as a sticker with no bubble, and the recipient can peel it onto any message in the conversation.

Terminal window
curl -X POST https://api.linqapp.com/api/partner/v3/chats/{chatId}/messages \
-H "Authorization: Bearer $LINQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": {
"parts": [
{
"type": "media",
"url": "https://cdn.linqapp.com/attachments/example/sticker.png",
"sticker": true
}
]
}
}'
  • Photos are cut out automatically. The subject is lifted off its background. An image that’s already cut out is sent as-is.
  • If no subject is found, the image sends as a photo.
  • Animated images send as animated stickers, without a cutout.
  • iMessage only. On SMS and RCS the image sends as a photo.

inline_stickers places sticker images in the line of text. Each entry replaces a character range of the text part’s value, and takes its image from exactly one of url or attachment_id.

Terminal window
curl -X POST https://api.linqapp.com/api/partner/v3/chats/{chatId}/messages \
-H "Authorization: Bearer $LINQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": {
"parts": [
{
"type": "text",
"value": "Happy birthday 🎂! 🎉🎉",
"inline_stickers": [
{
"range": [
15,
17
],
"attachment_id": "550e8400-e29b-41d4-a716-446655440000"
},
{
"range": [
19,
21
],
"attachment_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
},
{
"range": [
21,
23
],
"attachment_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
]
}
]
}
}'

The same array works on POST /v3/chats and POST /v3/messages, on any text part.

Field Required Type Description
range Yes array<integer> Character range `[start, end)` in the `value` string that the sticker replaces. `start` is inclusive, `end` is exclusive. Those characters are hidden on iMessage and sent as written on SMS and RCS. *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*
url No string (uri) Linq attachment URL of the sticker image — the `download_url` returned by `POST /v3/attachments`. The image must already be stored with us. To use an image from elsewhere, upload it with `POST /v3/attachments` first and pass `attachment_id`. Exactly one of `url` or `attachment_id` is required.
attachment_id No string (uuid) Reference to a sticker image pre-uploaded via `POST /v3/attachments`. Exactly one of `url` or `attachment_id` is required.

The sticker replaces the characters in its range. On SMS and RCS, recipients see those characters instead, and VoiceOver reads them aloud.

Use a placeholder that fits in the sentence, like an emoji or [cake]. For example, "Sip cup 🥤" with the range on 🥤 shows “Sip cup” followed by the sticker.

Ranges are [start, end) in UTF-16 code units, the same as text decorations. Most characters count as 1; some emoji count as 2.

  • 100 stickers and 10 different images per part. Copies of one image count as one.
  • Ranges can’t overlap each other or a text_decorations range, and can’t split a character. Can’t be combined with mention on the same part.
  • Animated images arrive as a still.
  • No error on SMS or RCS. The stickers are dropped and value is sent as written.

Text parts include an inline_stickers array in the send response, GET /v3/messages/{messageId}, GET /v3/chats/{chatId}/messages, and the message.* webhooks. Each entry has the range plus the image’s id, url, mime_type and file_name. It’s null on a part with no stickers.

inline_stickers is only set on messages you send. An inline sticker you receive arrives as a separate media part.

  • A peel can’t be removed. operation: "remove" with type: "sticker" is rejected, and there is no reaction.removed counterpart.
  • Stickers stack. Unlike a tapback, a second sticker doesn’t replace the first.
  • Only the sender can move a sticker. A recipient can’t drag, resize or rotate one you peeled. Placement is yours alone, on send or via PATCH.
  • iMessage only. A peel onto a chat on SMS or RCS is rejected with 2029. Check iMessage capability first, or send a tapback, which SMS and RCS do support.