Rewinding Agent Channels

Rewind takes an agent channel back to one of its top-level messages. Every message created after that message is hidden from every read, and the conversation continues from there. With inclusive, the message itself is hidden too. This is how an agent backend lets a user regenerate an answer or edit an earlier prompt.

Rewound messages are hidden, not deleted. They cannot be restored.

Rewind is in beta. It works on agent channels only, and Stream enables it per app: contact support to turn it on. Until it is enabled, the endpoint returns 403.

Who can rewind

Rewind is a server-side operation. It needs the RewindChannel permission, which only server-side requests and users with the admin role have. Users and guests cannot rewind an agent channel, not even one they created.

On a server-side request, user_id names the user the rewind is attributed to. It is optional.

Rewind a channel

Field Required Description
message_id Yes The top-level message to rewind to. It must be in the channel, visible, not deleted and not a reply. Every message created after it is hidden.
expected_last_message_id Yes The newest visible message your backend saw. The rewind fails with 409 rewind_conflict when it is no longer the newest one (see Concurrent changes).
inclusive No When true, message_id is hidden too and the message before it becomes the newest visible message. Defaults to false.
user_id No Server-side only. The user the rewind is attributed to.
$response = $client->rewindChannel("agent", "conversation-1", new Models\RewindChannelRequest(
    messageID: "prompt-2",
    expectedLastMessageID: "answer-3",
    inclusive: false,
));
echo $response->getData()->rewind->hiddenCountAtRewind;

The response carries the channel after the rewind and the rewind itself:

{
  "rewind": {
    "id": "8d1f0c7e-3a52-4b8e-9f61-2c4d7b0e5a19",
    "message_id": "prompt-2",
    "inclusive": false,
    "hidden_count_at_rewind": 2,
    "created_at": "2026-11-03T10:15:42.128Z"
  },
  "channel": { "cid": "agent:conversation-1", "...": "..." },
  "duration": "18.42ms"
}

hidden_count_at_rewind is the number of messages this rewind hid that were not hidden already.

Concurrent changes

expected_last_message_id protects the rewind from changes your backend did not see. If a message was sent, or another rewind landed, after you read the channel, the newest visible message is no longer the one you expected and the rewind fails with 409 and reason rewind_conflict. The error's exception_fields.last_message_id carries the actual newest visible message. Reload the channel, decide again, and retry.

Rewinding repeatedly

A channel can hold at most 100 separate hidden ranges. Overlapping and adjacent ranges count as one, so rewinding to the same message again and again, as a "regenerate" button does, never reaches the limit. Only a rewind that would add a 101st separate range fails, with reason too_many_rewinds.

Each rewind can only target a message that is still visible, so the visible history is always a single line. To keep the history that a rewind would hide, fork the channel first.

What a hidden message does

A hidden message is treated as if it did not exist, everywhere a client can see it:

  • Reads. It is left out of the channel's messages, pagination, pinned messages, replies and search. Getting it by id returns 404.
  • Unread counts. The rewind takes the hidden messages out of the members' channel unread counts.
  • Threads. A thread whose parent message is hidden is treated as missing by Query Threads and Get Thread. A Query Threads page can therefore hold fewer threads than limit and still have a next cursor. latest_replies leaves hidden replies out.
  • Quotes. A message that quotes a hidden message keeps its quoted_message_id, but is returned without the quoted_message object. Sending, updating or scheduling a new message that quotes a hidden message is rejected, as for a quote of a message that does not exist.
  • Reminders. A reminder on a hidden message is kept and returned without its message. When it is due, it sends no push, event or webhook.
  • Drafts. A draft whose quoted or parent message is hidden is kept and returned without quoted_message or parent_message.
  • Message history. The edit history of a hidden message is not returned.
  • Offline sync. /sync drops the events of hidden messages and replays channel.rewound, so a client that was offline during the rewind removes the messages it already holds.
  • Updates. Updating a hidden message returns 404.
  • Deletes. A hidden message can still be deleted, soft or hard, by a server-side request or by the message's own author, so that you can honor an erasure request. Any other user, an admin included, gets 404. A soft-deleted hidden message stays hidden. The delete sends no message.deleted over the WebSocket and no push. Webhooks still receive it.
  • New messages. A message sent after a rewind is always placed after the hidden messages, so it can never fall into the hidden range.

Known limitations

  • message_count on the channel and reply_count on a parent message still count hidden messages.
  • Thread unread counts are not recomputed after a rewind.
  • A member's last read message can point to a hidden message.
  • A channel export includes hidden messages, with nothing marking them as hidden.
  • For a moment after a rewind, a read can still return the messages it just hid.

Events

Event Sent to Description
channel.rewound Clients watching the channel, and webhooks Carries channel (after the rewind), rewind and user. Clients should reload the channel's messages when they receive it. It never carries a hidden message, and the range of hidden timestamps is not exposed.
notification.channel_rewound Connected clients of members who are not watching the channel, WebSocket only Carries channel, rewind and the member's unread counts after the rewind, so a channel list can refresh its preview. It is sent only when read_events is enabled on the channel type, which it is on agent by default, and to the first 100 members.

Neither event is sent as a push notification.

Errors

HTTP Code exception_fields.reason When
403 17 Rewind is not enabled for the app, or the caller does not have the RewindChannel permission.
400 4 The channel is not an agent channel, or message_id is a reply, deleted, hidden or not in the channel.
400 4 too_many_rewinds The rewind would give the channel more than 100 separate hidden ranges. exception_fields.limit carries the limit.
400 4 nothing_to_rewind message_id is the newest visible message and inclusive is not set, so nothing would be hidden.
409 125 rewind_conflict The newest visible message is not expected_last_message_id. exception_fields.last_message_id carries the actual one.
409 126 rewind_point_ambiguous Another visible message has the same created_at as message_id, so the two cannot be told apart.
409 131 fork_in_progress The channel is a fork whose history is still being copied. Rewind it once channel.forked arrives or its fork.status is no longer backfilling.