From fdceaece09b64b7315a70ce0db461cf79ffc5553 Mon Sep 17 00:00:00 2001 From: Perny Date: Sat, 27 Jun 2026 06:15:30 +0300 Subject: [PATCH 1/3] MSC4497: Filter state events by type in /state endpoint#4497 --- proposals/4497-state-event-type-filter.md | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 proposals/4497-state-event-type-filter.md diff --git a/proposals/4497-state-event-type-filter.md b/proposals/4497-state-event-type-filter.md new file mode 100644 index 00000000000..3fdd15cf5d9 --- /dev/null +++ b/proposals/4497-state-event-type-filter.md @@ -0,0 +1,100 @@ +# Filter state events by type in /state endpoint + +Currently, the `GET /_matrix/client/v3/rooms/{roomId}/state` endpoint returns all state events in a +room. For rooms with many state events, this can be inefficient when a client only needs events of +specific types. + +This proposal adds an optional `types` query parameter to the `/state` endpoint, allowing clients to +request only state events matching the specified event types. + + +## Proposal + +Add an optional `types` query parameter to the `GET /_matrix/client/v3/rooms/{roomId}/state` endpoint. + +### Query Parameters + +| Name | Type | Description | +|------|------|-------------| +| `types` | `[string]` | A JSON-encoded array of event types to include. If this list is absent then all event types are included. A `*` can be used as a wildcard to match any sequence of characters. | + +This follows the same semantics as the `types` field in `RoomEventFilter`: + +> A list of event types to include. If this list is absent then all event types are included. +> A `*` can be used as a wildcard to match any sequence of characters. + +### Examples + +Request all space child events: + +``` +GET /_matrix/client/v3/rooms/!roomid:example.org/state?types=%5B%22m.space.child%22%5D +``` + +Request multiple event types: + +``` +GET /_matrix/client/v3/rooms/!roomid:example.org/state?types=%5B%22m.room.name%22%2C%22m.room.topic%22%2C%22m.room.avatar%22%5D +``` +As `m.room.name`, `m.room.topic` and `m.room.avatar` are all states that typically only have one key, they could have +been fetched using the existing `GET /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}` endpoint. Using +the types query parameter makes this task not require seperate requests. + +Request all events in a namespace using wildcard: + +``` +GET /_matrix/client/v3/rooms/!roomid:example.org/state?types=%5B%22org.example.*%22%5D +``` + +### Behavior + +- When `types` is not provided, the endpoint behaves exactly as it does now, returning all state events. +- When `types` is an empty array `[]`, no state events are returned. +- Following `RoomEventFilter`, wildcard matching uses `*` to match any sequence of characters. + + +## Potential issues + +JSON-encoded arrays in query parameters are awkward to work with. They require URL encoding, and +some HTTP client libraries don't handle this well out of the box. However, this approach maintains +consistency with `RoomEventFilter` semantics and avoids inventing a new format for the same +filtering concept. + + +## Alternatives + +### Use /sync with a filter + +Clients could use `/sync` with a `RoomFilter` that specifies the desired `rooms` and a `StateFilter` +with the desired `types`. However, the `/sync` response structure is significantly more complex than +`/state`, and filtering to a single room requires either listing it explicitly or using a filter ID +created via `POST /filter`. + +### Accept a full StateFilter + +Instead of just `types`, the endpoint could accept a full `StateFilter` object (with `types`, +`not_types`, `senders`, `not_senders`, etc.). However, for most usecases `StateFilter` provides +a lot more than what is needed to read state. + +### Add individual query parameters per type + +Instead of a JSON array, we could use repeated query parameters like +`type=m.room.power_levels&type=m.room.name`. This would be simpler to construct but wouldn't +support wildcards as elegantly and deviates from the established `RoomEventFilter` pattern. + + +## Security considerations + +None. + +## Unstable prefix + +While this MSC is not yet part of the spec, implementations should use `cc.koja.types` as the query +parameter name. Once this MSC is merged, implementations can use `types`. + +Clients can detect server support by checking for the presence of the `cc.koja.types` flag in the +`unstable_features` section of the `/versions` response. + +## Dependencies + +None. From 51fdc769819d77e53a27c36181d4751daadb53ac Mon Sep 17 00:00:00 2001 From: Perny <83672513+pernydev@users.noreply.github.com> Date: Mon, 29 Jun 2026 20:24:38 +0300 Subject: [PATCH 2/3] Fix spelling error --- proposals/4497-state-event-type-filter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/4497-state-event-type-filter.md b/proposals/4497-state-event-type-filter.md index 3fdd15cf5d9..60be6532736 100644 --- a/proposals/4497-state-event-type-filter.md +++ b/proposals/4497-state-event-type-filter.md @@ -38,7 +38,7 @@ GET /_matrix/client/v3/rooms/!roomid:example.org/state?types=%5B%22m.room.name%2 ``` As `m.room.name`, `m.room.topic` and `m.room.avatar` are all states that typically only have one key, they could have been fetched using the existing `GET /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}` endpoint. Using -the types query parameter makes this task not require seperate requests. +the types query parameter makes this task not require separate requests. Request all events in a namespace using wildcard: From 2dc31f89b0f89d2cd2631ab474b18ee0fb079e50 Mon Sep 17 00:00:00 2001 From: Perny <83672513+pernydev@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:50:03 +0300 Subject: [PATCH 3/3] fix: name of RoomEventFilter --- proposals/4497-state-event-type-filter.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/4497-state-event-type-filter.md b/proposals/4497-state-event-type-filter.md index 60be6532736..4c86a45869e 100644 --- a/proposals/4497-state-event-type-filter.md +++ b/proposals/4497-state-event-type-filter.md @@ -65,15 +65,15 @@ filtering concept. ### Use /sync with a filter -Clients could use `/sync` with a `RoomFilter` that specifies the desired `rooms` and a `StateFilter` +Clients could use `/sync` with a `RoomFilter` that specifies the desired `rooms` and a `RoomEventFilter` with the desired `types`. However, the `/sync` response structure is significantly more complex than `/state`, and filtering to a single room requires either listing it explicitly or using a filter ID created via `POST /filter`. -### Accept a full StateFilter +### Accept a full RoomEventFilter -Instead of just `types`, the endpoint could accept a full `StateFilter` object (with `types`, -`not_types`, `senders`, `not_senders`, etc.). However, for most usecases `StateFilter` provides +Instead of just `types`, the endpoint could accept a full `RoomEventFilter` object (with `types`, +`not_types`, `senders`, `not_senders`, etc.). However, for most usecases `RoomEventFilter` provides a lot more than what is needed to read state. ### Add individual query parameters per type