Skip to main content
Use pin APIs to surface one important message above a livestream chat so every viewer sees it, no matter how fast the feed scrolls. Pin state is owned by the server and exposed on the channel as pinnedMessage. A channel holds at most one pinned message at a time.
Pinning is available on live channels only, the channel type attached to a livestream room. The server rejects pin requests on conversation, community, broadcast, standard, and private channels.The Flutter and React Native SDKs do not ship pin support.

Platform Surface

Parameters

Who Can Pin

The server authorizes pin and unpin with the PIN_MESSAGE channel permission. Default moderator roles carry it, so channel moderators can pin. A livestream host and co-hosts receive the channel moderator role when the room is created or when a co-host joins, so they can pin as well. Network admins with the moderate-channel admin permission can pin from the Console. A message author cannot pin their own message by authorship alone. Only role holders can pin. Check the permission before you show a pin control:
On Android the check is a Flowable and re-emits when the user’s channel membership changes. On iOS the check is one-shot: re-run it when the channel, room, the current user’s channel membership, or the current user’s own record updates, and after a 403. Permission changes reach the client over realtime events by scope: a channel-level role change (moderator or co-host) over the channel.roleAdded / channel.roleRemoved events, which update the user’s channel permissions; and a network-level change made from the Console over the user.updated event, which updates the user’s network permissions. On iOS, user.updated is delivered only while the current user’s events are subscribed (AmityUser.subscribeEvent(.user)); the pre-built livestream chat UI subscribes this automatically while it is open, and unsubscribes when it closes. Because the permission check combines the user’s network and channel permissions, re-checking on either update reflects a mid-stream change with no user action, and the 403 re-check is a backstop.
Roles are seeded when a network is created. On a network created before pin support shipped, existing roles may not include PIN_MESSAGE until the role backfill has run for that network. Until then the permission check returns false and every pin request returns 403. Contact support if pin controls never appear on an older network.

Pin A Message

Pin a message in its livestream channel. If another message is already pinned, the new pin replaces it in one step. You do not need to unpin first. The SDK calls POST /api/v5/messages/{messageId}/pin.
The call returns the updated channel with the pinned message set. The SDK writes the channel into its cache, so any active channel observer for that channel fires immediately, without waiting for the realtime event. Pinning the message that is already pinned returns a 400 error. Pinning a deleted message, or a message whose author is banned from the channel or globally banned, also returns 400. Pin state is unchanged on any error.

Unpin A Message

Remove the current pin. Pass the messageId of the message that is currently pinned. The SDK calls DELETE /api/v5/messages/{messageId}/pin.
The server rejects an unpin with 400 when messageId is not the current pin. This is deliberate. A stale client cannot clear a pin that someone else has since replaced. When you receive that error, re-read the channel or rely on the next channel.messagePinned event to get the current pin. Unpin is allowed regardless of stream state, so a moderator can clean up after a stream ends.

Read The Pinned Message

The pinned message lives on the channel, so observe the channel you already hold for the live chat. The field is null when nothing is pinned. On TypeScript it is typed optional, so a channel payload that omits it reads as undefined. Treat null and undefined the same way, as the ?? null in the example does.

Pinned message shape

The pinned message carries a snapshot of the message body plus who pinned it and when. It is not a full message object, so use the fields below rather than message-repository helpers. Android exposes each field through the getter named in the third column. The response and the pin event include the pinned message author in their users payload, so the author is usually already in the user cache when you render the banner.

Listen For Pin Changes

Two realtime events arrive on the channel topic that live chat clients already subscribe to. You do not need an extra topic subscription. On every platform the SDK handles both events internally: it updates the cached channel and the channel live object emits. The TypeScript SDK also exposes the two events as callbacks for cases where you need a hook separate from the channel observer. On iOS and Android there is no separate callback. Observe the channel and compare the pinned message ID between emissions to tell a pin from an unpin.
Realtime delivery on iOS and Android requires the channel topic to be subscribed, which the live chat already does for the channel it renders. If you observe a channel outside a live chat screen, subscribe to its topic first as described in Chat Realtime Events. Treat every messagePinned payload as the full current state and apply the last one you receive. Do not treat it as an increment. Replacing a pin emits one messagePinned event with the new message, not an unpin followed by a pin.

Automatic unpin

The server clears the pin and emits channel.messageUnpinned when:
  • The pinned message is deleted.
  • The pinned message author is banned from the channel or globally banned. The author’s messages are deleted as part of the ban.
A community ban does not affect the pin. The SDK also clears the cached pinned message when it receives a message.deleted event for the pinned message, so the channel stays correct even if the unpin event is missed.
Realtime events are not replayed after a reconnect. A client that was offline while the pin changed receives nothing on reconnect. Read the channel again after reconnecting and use the channel’s pinned message as the source of truth.

Server Rules And Errors

Every 400 condition shares the code 400000. Only the server message string tells them apart, so do not branch on the code to decide which one happened. Pin state is never changed by a failed request, so a client does not need to roll anything back. Re-read the channel, or wait for the next event, and render what it says.

Get a Channel

Observe the channel live object that carries the pinned message.

Roles and Permissions

Check PIN_MESSAGE and other channel permissions before showing controls.

Livestream UIKit

Ready-made pin action and pinned message banner in the livestream chat.