> ## Documentation Index
> Fetch the complete documentation index at: https://learn.social.plus/llms.txt
> Use this file to discover all available pages before exploring further.

# Query and Filter Messages

> Query chat messages by subchannel, type, tags, deleted state, parent message, or around-message context.

Use message queries to build timelines, reply threads, media views, and jump-to-message flows. All platforms start from a `subChannelId`; optional filters narrow the result set.

For chat timelines, prefer live collections or reactive streams where the platform provides them. They keep edits, deletes, reactions, and newly created messages in sync without a manual refresh loop.

## Filter Surface

| Filter           | TypeScript                       | iOS                              | Android                              | Flutter                              |
| ---------------- | -------------------------------- | -------------------------------- | ------------------------------------ | ------------------------------------ |
| Subchannel       | `subChannelId`                   | `subChannelId`                   | `getMessages(subChannelId)`          | `getMessages(subChannelId)`          |
| Tags             | `includingTags`, `excludingTags` | `includingTags`, `excludingTags` | `includingTags()`, `excludingTags()` | `includingTags()`, `excludingTags()` |
| Type             | `type`                           | `type`                           | `type()`                             | `type()`                             |
| Deleted messages | `includeDeleted`                 | Not exposed on query options     | `includeDeleted()`                   | `includeDeleted()`                   |
| Replies          | `parentId`                       | `messageParentFilter`            | `parentId()`                         | `parentId()`                         |
| Jump context     | `aroundMessageId`                | `aroundMessageId`                | `aroundMessageId()`                  | `aroundMessageId()`                  |

## Parameters

| Parameter                          | Required | Description                                                                               |
| ---------------------------------- | -------- | ----------------------------------------------------------------------------------------- |
| `subChannelId`                     | Yes      | Target subchannel whose messages should be queried.                                       |
| `includingTags` / `excludingTags`  | No       | Include or exclude messages with specific app-defined tags.                               |
| `type`                             | No       | Restrict results to one message type, such as text, image, file, video, audio, or custom. |
| `includeDeleted`                   | No       | Include soft-deleted messages where the platform exposes the filter.                      |
| `parentId` / `messageParentFilter` | No       | Query replies for a parent message instead of the main timeline.                          |
| `aroundMessageId`                  | No       | Load messages around a target message for deep-link or jump-to-message flows.             |
| `sortBy` / `stackFromEnd`          | No       | Control timeline ordering where the platform exposes sort options.                        |
| Pagination controls                | No       | Use callbacks, live collections, or paging data to load additional results.               |

## Query A Timeline

Query the main message timeline for a subchannel with optional tag and sort filters.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { MessageRepository } from '@amityco/ts-sdk';

  const unsubscribe = MessageRepository.getMessages(
    {
      subChannelId,
      includingTags: ['public'],
      excludingTags: ['hidden'],
      sortBy: 'segmentDesc',
    },
    ({ data: messages, onNextPage, hasNextPage, loading, error }) => {
      if (error) handleError(error);

      if (!loading && messages) {
        renderResults(messages);
      }

      if (hasNextPage) onNextPage?.();
    },
  );

  unsubscribe();
  ```

  ```swift iOS theme={null}
  let options = AmityMessageQueryOptions(
      subChannelId: "sub-channel-id",
      includingTags: ["public"],
      excludingTags: ["hidden"],
      sortOption: .lastCreated
  )

  let messages = messageRepository.getMessages(options: options)
  token = messages.observe { collection, error in
      if let error {
          handleError(error)
          return
      }

      showSuccessMessage(collection.snapshots.count)
  }
  ```

  ```kotlin Android theme={null}
  val includingTags = AmityTags().apply { add("public") }
  val excludingTags = AmityTags().apply { add("hidden") }

  val disposable = messageRepository
      .getMessages(subChannelId = subChannelId)
      .includingTags(includingTags)
      .excludingTags(excludingTags)
      .sortBy(AmityMessageQuerySortOption.LAST_CREATED)
      .build()
      .query()
      .subscribe(
          { pagingData -> getPagingData(pagingData) },
          { error -> handleGeneralError(error) },
      )
  ```

  ```dart Flutter theme={null}
  final liveCollection = AmityChatClient.newMessageRepository()
      .getMessages(subChannelId)
      .includingTags(['public'])
      .excludingTags(['hidden'])
      .stackFromEnd(true)
      .getLiveCollection();

  liveCollection.getStreamController().stream.listen((messages) {
    final count = messages.length;
  });

  liveCollection.loadNext();
  ```
</CodeGroup>

## Query By Type Or Deleted State

Use message type and deleted-state filters to build focused views such as media galleries or moderation queues.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { MessageRepository } from '@amityco/ts-sdk';

  const unsubscribe = MessageRepository.getMessages(
    {
      subChannelId,
      type: 'image',
      includeDeleted: false,
    },
    ({ data: messages }) => {
      renderResults(messages);
    },
  );

  unsubscribe();
  ```

  ```swift iOS theme={null}
  let options = AmityMessageQueryOptions(
      subChannelId: "sub-channel-id",
      type: .image,
      sortOption: .lastCreated
  )

  let messages = messageRepository.getMessages(options: options)
  showSuccessMessage(messages)
  ```

  ```kotlin Android theme={null}
  val disposable = messageRepository
      .getMessages(subChannelId = subChannelId)
      .type(AmityMessage.DataType.IMAGE)
      .includeDeleted(includeDeleted = false)
      .build()
      .query()
      .subscribe(
          { pagingData -> getPagingData(pagingData) },
          { error -> handleGeneralError(error) },
      )
  ```

  ```dart Flutter theme={null}
  final imageMessages = await AmityChatClient.newMessageRepository()
      .getMessages(subChannelId)
      .type(AmityMessageDataType.IMAGE)
      .includeDeleted(false)
      .query();

  final count = imageMessages.length;
  ```
</CodeGroup>

## Query Replies

Use a parent message ID to fetch replies to that message. Use the no-parent/default query for the main timeline.

Query replies with `parentId` when rendering a message thread.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { MessageRepository } from '@amityco/ts-sdk';

  const unsubscribe = MessageRepository.getMessages(
    {
      subChannelId,
      parentId: messageId,
      sortBy: 'segmentAsc',
    },
    ({ data: replies }) => {
      renderResults(replies);
    },
  );

  unsubscribe();
  ```

  ```swift iOS theme={null}
  let options = AmityMessageQueryOptions(
      subChannelId: "sub-channel-id",
      messageParentFilter: .parent(id: "parent-message-id"),
      sortOption: .firstCreated
  )

  let replies = messageRepository.getMessages(options: options)
  showSuccessMessage(replies)
  ```

  ```kotlin Android theme={null}
  val disposable = messageRepository
      .getMessages(subChannelId = subChannelId)
      .parentId(parentId = messageId)
      .sortBy(AmityMessageQuerySortOption.FIRST_CREATED)
      .build()
      .query()
      .subscribe(
          { pagingData -> getPagingData(pagingData) },
          { error -> handleGeneralError(error) },
      )
  ```

  ```dart Flutter theme={null}
  final replies = await AmityChatClient.newMessageRepository()
      .getMessages(subChannelId)
      .parentId(messageId)
      .query();

  final replyCount = replies.length;
  ```
</CodeGroup>

## Jump To A Message

Use `aroundMessageId` when your app opens a deep link or search result and needs the target message plus nearby context.

Query around a target message to load nearby context for deep links and search results.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { MessageRepository } from '@amityco/ts-sdk';

  const unsubscribe = MessageRepository.getMessages(
    {
      subChannelId,
      aroundMessageId: messageId,
    },
    ({ data: messages, hasPrevPage, hasNextPage }) => {
      renderResults({ messages, hasPrevPage, hasNextPage });
    },
  );

  unsubscribe();
  ```

  ```swift iOS theme={null}
  let options = AmityMessageQueryOptions(
      subChannelId: "sub-channel-id",
      aroundMessageId: "message-id",
      sortOption: .lastCreated
  )

  let messages = messageRepository.getMessages(options: options)
  showSuccessMessage(messages)
  ```

  ```kotlin Android theme={null}
  val disposable = messageRepository
      .getMessages(subChannelId = subChannelId)
      .aroundMessageId(messageId = messageId)
      .build()
      .query()
      .subscribe(
          { pagingData -> getPagingData(pagingData) },
          { error -> handleGeneralError(error) },
      )
  ```

  ```dart Flutter theme={null}
  final messagesAroundTarget = await AmityChatClient.newMessageRepository()
      .getMessages(subChannelId)
      .aroundMessageId(messageId)
      .query();

  final count = messagesAroundTarget.length;
  ```
</CodeGroup>

## Related Topics

<CardGroup cols={3}>
  <Card title="Send Messages" href="../message-creation/send-a-message" icon="paper-plane">
    Create messages that appear in the queried subchannel.
  </Card>

  <Card title="Get a Message" href="./get-and-view-a-message" icon="eye">
    Retrieve or observe one message by ID.
  </Card>

  <Card title="Edit and Delete" href="./edit-and-delete-messages" icon="pen-to-square">
    Update queried messages after creation.
  </Card>
</CardGroup>
