diff --git a/changelogs/application_service/newsfragments/1094.feature b/changelogs/application_service/newsfragments/1094.feature
new file mode 100644
index 00000000..e1b2d5cb
--- /dev/null
+++ b/changelogs/application_service/newsfragments/1094.feature
@@ -0,0 +1 @@
+Add timestamp massaging as per [MSC3316](https://github.com/matrix-org/matrix-spec-proposals/pull/3316).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1003.clarification b/changelogs/client_server/newsfragments/1003.clarification
index efe68e48..9b2788cc 100644
--- a/changelogs/client_server/newsfragments/1003.clarification
+++ b/changelogs/client_server/newsfragments/1003.clarification
@@ -1 +1 @@
-Adjust the OpenAPI specification so that the type `Flow information` is explicitly defined when the CS spec is rendered.
+Adjust the OpenAPI specification so that the type `Flow information` is explicitly defined when the client-server API is rendered.
diff --git a/changelogs/client_server/newsfragments/1056.feature b/changelogs/client_server/newsfragments/1056.feature
new file mode 100644
index 00000000..2f8febb7
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1056.feature
@@ -0,0 +1 @@
+Add refresh tokens, per [MSC2918](https://github.com/matrix-org/matrix-spec-proposals/pull/2918).
diff --git a/changelogs/client_server/newsfragments/1059.clarification b/changelogs/client_server/newsfragments/1059.clarification
index 2e94fb7f..ca5f3aea 100644
--- a/changelogs/client_server/newsfragments/1059.clarification
+++ b/changelogs/client_server/newsfragments/1059.clarification
@@ -1 +1 @@
-Fix room state 400 code error examples to match known error codes.
+Fix various typos throughout the specification.
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1062.feature.1 b/changelogs/client_server/newsfragments/1062.feature.1
new file mode 100644
index 00000000..6c669e43
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1062.feature.1
@@ -0,0 +1 @@
+Relax the restrictions on Rich Replies, as per [MSC3676](https://github.com/matrix-org/matrix-spec-proposals/pull/3676).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1062.feature.2 b/changelogs/client_server/newsfragments/1062.feature.2
new file mode 100644
index 00000000..8234ef2a
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1062.feature.2
@@ -0,0 +1 @@
+Describe a structured system for event relationships, as per [MSC2674](https://github.com/matrix-org/matrix-spec-proposals/pull/2674).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1062.feature.3 b/changelogs/client_server/newsfragments/1062.feature.3
new file mode 100644
index 00000000..d2a376af
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1062.feature.3
@@ -0,0 +1 @@
+Describe how relationships between events can be "aggregated", as per [MSC2675](https://github.com/matrix-org/matrix-spec-proposals/pull/2675) and [MSC3666](https://github.com/matrix-org/matrix-spec-proposals/pull/3666).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1097.clarification b/changelogs/client_server/newsfragments/1097.clarification
new file mode 100644
index 00000000..3ccb2333
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1097.clarification
@@ -0,0 +1 @@
+Fix various typos throughout the specification.
diff --git a/changelogs/client_server/newsfragments/1099.feature b/changelogs/client_server/newsfragments/1099.feature
new file mode 100644
index 00000000..632a1c46
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1099.feature
@@ -0,0 +1 @@
+Add support for a new `knock_restricted` join rule in supported room versions, as per [MSC3787](https://github.com/matrix-org/matrix-spec-proposals/pull/3787).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1100.clarification b/changelogs/client_server/newsfragments/1100.clarification
new file mode 100644
index 00000000..e17a2538
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1100.clarification
@@ -0,0 +1 @@
+Clarify that state keys starting with `@` are in fact reserved. Regressed from [#3658](https://github.com/matrix-org/matrix-spec-proposals/pull/3658).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1101.deprecation b/changelogs/client_server/newsfragments/1101.deprecation
new file mode 100644
index 00000000..922a2a0a
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1101.deprecation
@@ -0,0 +1 @@
+Deprecate the `sender_key` and `device_id` on `m.megolm.v1.aes-sha2` events, and the `sender_key` on `m.room_key_request` to-device messages, as per [MSC3700](https://github.com/matrix-org/matrix-spec-proposals/pull/3700).
\ No newline at end of file
diff --git a/changelogs/client_server/newsfragments/1110.clarification b/changelogs/client_server/newsfragments/1110.clarification
new file mode 100644
index 00000000..3ccb2333
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1110.clarification
@@ -0,0 +1 @@
+Fix various typos throughout the specification.
diff --git a/changelogs/client_server/newsfragments/1113.feature b/changelogs/client_server/newsfragments/1113.feature
new file mode 100644
index 00000000..2f8febb7
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1113.feature
@@ -0,0 +1 @@
+Add refresh tokens, per [MSC2918](https://github.com/matrix-org/matrix-spec-proposals/pull/2918).
diff --git a/changelogs/client_server/newsfragments/1115.clarification b/changelogs/client_server/newsfragments/1115.clarification
new file mode 100644
index 00000000..3ccb2333
--- /dev/null
+++ b/changelogs/client_server/newsfragments/1115.clarification
@@ -0,0 +1 @@
+Fix various typos throughout the specification.
diff --git a/changelogs/client_server/newsfragments/3681.clarification b/changelogs/client_server/newsfragments/3681.clarification
index f7c29003..ca5f3aea 100644
--- a/changelogs/client_server/newsfragments/3681.clarification
+++ b/changelogs/client_server/newsfragments/3681.clarification
@@ -1 +1 @@
-Fix broken syntax in Server Access Control Lists definition.
\ No newline at end of file
+Fix various typos throughout the specification.
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1037.clarification b/changelogs/room_versions/newsfragments/1037.clarification
index 9ac53c6d..e8aa3349 100644
--- a/changelogs/room_versions/newsfragments/1037.clarification
+++ b/changelogs/room_versions/newsfragments/1037.clarification
@@ -1,2 +1 @@
-Improve readability of definitions in the state resolution v2 algorithm.
-
+Improve readability and understanding of the state resolution algorithms.
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1042.clarification b/changelogs/room_versions/newsfragments/1042.clarification
new file mode 100644
index 00000000..e8aa3349
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/1042.clarification
@@ -0,0 +1 @@
+Improve readability and understanding of the state resolution algorithms.
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1043.clarification b/changelogs/room_versions/newsfragments/1043.clarification
index 49e552f4..e8aa3349 100644
--- a/changelogs/room_versions/newsfragments/1043.clarification
+++ b/changelogs/room_versions/newsfragments/1043.clarification
@@ -1 +1 @@
-Adjust mathematical notation used in the description of state resolution to render better in browsers.
\ No newline at end of file
+Improve readability and understanding of the state resolution algorithms.
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1050.clarification b/changelogs/room_versions/newsfragments/1050.clarification
index 0da1098a..f548b987 100644
--- a/changelogs/room_versions/newsfragments/1050.clarification
+++ b/changelogs/room_versions/newsfragments/1050.clarification
@@ -1 +1 @@
-Add cross-references to PDU content definitions from the authorisation rules.
+Improve readability of the authorization rules.
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1093.clarification b/changelogs/room_versions/newsfragments/1093.clarification
index 6176b102..06145378 100644
--- a/changelogs/room_versions/newsfragments/1093.clarification
+++ b/changelogs/room_versions/newsfragments/1093.clarification
@@ -1 +1 @@
-Auth rules: clarify that the resident server must sign a restricted join event.
+For room versions 8, 9, and 10: clarify which homeserver is required to sign the join event.
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1099.clarification b/changelogs/room_versions/newsfragments/1099.clarification
new file mode 100644
index 00000000..272aec3e
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/1099.clarification
@@ -0,0 +1 @@
+Clarify that room versions 1 through 9 accept stringy power levels, as noted by [MSC3667](https://github.com/matrix-org/matrix-spec-proposals/pull/3667).
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1099.feature.1 b/changelogs/room_versions/newsfragments/1099.feature.1
new file mode 100644
index 00000000..d8fabdba
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/1099.feature.1
@@ -0,0 +1 @@
+Add room version 10 as per [MSC3604](https://github.com/matrix-org/matrix-spec-proposals/pull/3604).
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1099.feature.2 b/changelogs/room_versions/newsfragments/1099.feature.2
new file mode 100644
index 00000000..b89704b8
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/1099.feature.2
@@ -0,0 +1 @@
+Enforce integer power levels in room version 10 as per [MSC3667](https://github.com/matrix-org/matrix-spec-proposals/pull/3667).
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/1099.feature.3 b/changelogs/room_versions/newsfragments/1099.feature.3
new file mode 100644
index 00000000..b10228de
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/1099.feature.3
@@ -0,0 +1 @@
+Add a `knock_restricted` join rule supported by room version 10 as per [MSC3787](https://github.com/matrix-org/matrix-spec-proposals/pull/3787).
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/3737.clarification b/changelogs/room_versions/newsfragments/3737.clarification
index c3b51679..6caf519a 100644
--- a/changelogs/room_versions/newsfragments/3737.clarification
+++ b/changelogs/room_versions/newsfragments/3737.clarification
@@ -1 +1 @@
-Fix join membership auth rules when `join_rule` is `knock`.
+For room versions 7, 8, 9, and 10: fix join membership authorization rules when `join_rule` is `knock`.
diff --git a/changelogs/room_versions/newsfragments/3739.feature b/changelogs/room_versions/newsfragments/3739.feature
index c20ec3ad..ddb88446 100644
--- a/changelogs/room_versions/newsfragments/3739.feature
+++ b/changelogs/room_versions/newsfragments/3739.feature
@@ -1 +1 @@
-Update the default room version to 9.
\ No newline at end of file
+Update the default room version to 9 as per [MSC3589](https://github.com/matrix-org/matrix-spec-proposals/pull/3589).
\ No newline at end of file
diff --git a/changelogs/server_server/newsfragments/1038.clarification b/changelogs/server_server/newsfragments/1038.clarification
index 39fbeddb..ad1ca8f0 100644
--- a/changelogs/server_server/newsfragments/1038.clarification
+++ b/changelogs/server_server/newsfragments/1038.clarification
@@ -1 +1 @@
-Fix origin server name in S2S Request Authentication example.
+Clarify the format for the Authorization header.
diff --git a/changelogs/server_server/newsfragments/1042.clarification b/changelogs/server_server/newsfragments/1042.clarification
deleted file mode 100644
index 2f3fad6f..00000000
--- a/changelogs/server_server/newsfragments/1042.clarification
+++ /dev/null
@@ -1 +0,0 @@
-Clarify the meaning of "unconflicted state map" and "auth chain" in state res v2.
diff --git a/changelogs/server_server/newsfragments/1045.clarification b/changelogs/server_server/newsfragments/1045.clarification
index 7b805569..adb3ec16 100644
--- a/changelogs/server_server/newsfragments/1045.clarification
+++ b/changelogs/server_server/newsfragments/1045.clarification
@@ -1 +1 @@
-Expand a little on what it means for a PDU to be valid when discussing checks on PDUs.
+Clarify what a "valid event" means when performing checks on a received PDU.
\ No newline at end of file
diff --git a/changelogs/server_server/newsfragments/1055.clarification b/changelogs/server_server/newsfragments/1055.clarification
index 748f7793..f9394c6a 100644
--- a/changelogs/server_server/newsfragments/1055.clarification
+++ b/changelogs/server_server/newsfragments/1055.clarification
@@ -1 +1 @@
-Clarify that valid_until_ts is in milliseconds, like other timestamps used in Matrix
+Clarify that `valid_until_ts` is in milliseconds, like other timestamps used in Matrix.
diff --git a/changelogs/server_server/newsfragments/1067.feature b/changelogs/server_server/newsfragments/1067.feature
index 1e88a3d9..0b067b36 100644
--- a/changelogs/server_server/newsfragments/1067.feature
+++ b/changelogs/server_server/newsfragments/1067.feature
@@ -1 +1 @@
-Add a destination property to the Authorization header.
+Add a `destination` property to the Authorization header, as per [MSC3383](https://github.com/matrix-org/matrix-spec-proposals/pull/3383).
diff --git a/changelogs/server_server/newsfragments/1070.clarification b/changelogs/server_server/newsfragments/1070.clarification
index 6661503e..ef4b1e6a 100644
--- a/changelogs/server_server/newsfragments/1070.clarification
+++ b/changelogs/server_server/newsfragments/1070.clarification
@@ -1 +1 @@
-Clarify that checks on PDUs should refer to the state _before_ an event.
+Clarify that checks on PDUs should refer to the state *before* an event.
diff --git a/changelogs/server_server/newsfragments/1099.clarification b/changelogs/server_server/newsfragments/1099.clarification
new file mode 100644
index 00000000..76ce9849
--- /dev/null
+++ b/changelogs/server_server/newsfragments/1099.clarification
@@ -0,0 +1 @@
+Clarify the historical handling of non-integer power levels.
\ No newline at end of file
diff --git a/changelogs/server_server/newsfragments/1110.clarification b/changelogs/server_server/newsfragments/1110.clarification
new file mode 100644
index 00000000..3ccb2333
--- /dev/null
+++ b/changelogs/server_server/newsfragments/1110.clarification
@@ -0,0 +1 @@
+Fix various typos throughout the specification.
diff --git a/changelogs/server_server/newsfragments/998.clarification b/changelogs/server_server/newsfragments/998.clarification
index c285269a..495fdade 100644
--- a/changelogs/server_server/newsfragments/998.clarification
+++ b/changelogs/server_server/newsfragments/998.clarification
@@ -1 +1 @@
-Remove `origin` field from PDUs which exists on many but not all PDUs in practice and doesn't serve an actual purpose.
+Remove largely unused `origin` field from PDUs.
diff --git a/content/application-service-api.md b/content/application-service-api.md
index 07362c51..61227660 100644
--- a/content/application-service-api.md
+++ b/content/application-service-api.md
@@ -300,13 +300,38 @@ An example request would be:
#### Timestamp massaging
-Previous drafts of the Application Service API permitted application
-services to alter the timestamp of their sent events by providing a `ts`
-query parameter when sending an event. This API has been excluded from
-the first release due to design concerns, however some servers may still
-support the feature. Please visit [issue
-\#1585](https://github.com/matrix-org/matrix-doc/issues/1585) for more
-information.
+{{% added-in v="1.3" %}}
+
+Application services can alter the timestamp associated with an event, allowing
+the application service to better represent the "real" time an event was sent
+at. While this doesn't affect the server-side ordering of the event, it can allow
+an application service to better represent when an event would have been sent/received
+at, such as in the case of bridges where the remote network might have a slight
+delay and the application service wishes to bridge the proper time onto the message.
+
+When authenticating requests as an application service, the caller can append a `ts`
+query string argument to change the `origin_server_ts` of the resulting event. Attempting
+to set the timestamp to anything other than what is accepted by `origin_server_ts` should
+be rejected by the server as a bad request.
+
+When not present, the server's behaviour is unchanged: the local system time of the server
+will be used to provide a timestamp, representing "now".
+
+The `ts` query string argument is only valid on the following endpoints:
+
+* [`PUT /rooms/{roomId}/send/{eventType}/{txnId}`](/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid)
+* [`PUT /rooms/{roomId}/state/{eventType}/{stateKey}`](/client-server-api/#put_matrixclientv3roomsroomidstateeventtypestatekey)
+
+Other endpoints, such as `/kick`, do not support `ts`: instead, callers can use the
+`PUT /state` endpoint to mimic the behaviour of the other APIs.
+
+{{% boxes/warning %}}
+Changing the time of an event does not change the server-side (DAG) ordering for the
+event. The event will still be appended at the tip of the DAG as though the timestamp
+was set to "now". Future MSCs, like [MSC2716](https://github.com/matrix-org/matrix-spec-proposals/pull/2716),
+are expected to provide functionality which can allow DAG order manipulation (for history
+imports and similar behaviour).
+{{% /boxes/warning %}}
#### Server admin style permissions
diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md
index da19a7de..00e3f4ad 100644
--- a/content/client-server-api/_index.md
+++ b/content/client-server-api/_index.md
@@ -71,7 +71,7 @@ These error codes can be returned by any API endpoint:
Forbidden access, e.g. joining a room without permission, failed login.
`M_UNKNOWN_TOKEN`
-The access token specified was not recognised.
+The access or refresh token specified was not recognised.
An additional response parameter, `soft_logout`, might be present on the
response for 401 HTTP status codes. See [the soft logout
@@ -314,7 +314,8 @@ Most API endpoints require the user to identify themselves by presenting
previously obtained credentials in the form of an `access_token` query
parameter or through an Authorization Header of `Bearer $access_token`.
An access token is typically obtained via the [Login](#login) or
-[Registration](#account-registration-and-management) processes.
+[Registration](#account-registration-and-management) processes. Access tokens
+can expire; a new access token can be generated by using a refresh token.
{{% boxes/note %}}
This specification does not mandate a particular format for the access
@@ -338,40 +339,94 @@ inaccessible for the client.
When credentials are required but missing or invalid, the HTTP call will
return with a status of 401 and the error code, `M_MISSING_TOKEN` or
-`M_UNKNOWN_TOKEN` respectively.
+`M_UNKNOWN_TOKEN` respectively. Note that an error code of `M_UNKNOWN_TOKEN`
+could mean one of four things:
+
+1. the access token was never valid.
+2. the access token has been logged out.
+3. the access token has been [soft logged out](#soft-logout).
+4. {{< added-in v="1.3" >}} the access token [needs to be refreshed](#refreshing-access-tokens).
+
+When a client receives an error code of `M_UNKNOWN_TOKEN`, it should:
+
+- attempt to [refresh the token](#refreshing-access-tokens), if it has a refresh
+ token;
+- if [`soft_logout`](#soft-logout) is set to `true`, it can offer to
+ re-log in the user, retaining any of the client's persisted
+ information;
+- otherwise, consider the user as having been logged out.
### Relationship between access tokens and devices
Client [devices](../index.html#devices) are closely related to access
-tokens. Matrix servers should record which device each access token is
-assigned to, so that subsequent requests can be handled correctly.
+tokens and refresh tokens. Matrix servers should record which device
+each access token and refresh token are assigned to, so that
+subsequent requests can be handled correctly. When a refresh token is
+used to generate a new access token and refresh token, the new access
+and refresh tokens are now bound to the device associated with the
+initial refresh token.
By default, the [Login](#login) and [Registration](#account-registration-and-management)
processes auto-generate a new `device_id`. A client is also free to
generate its own `device_id` or, provided the user remains the same,
reuse a device: in either case the client should pass the `device_id` in
the request body. If the client sets the `device_id`, the server will
-invalidate any access token previously assigned to that device. There is
-therefore at most one active access token assigned to each device at any
-one time.
+invalidate any access and refresh tokens previously assigned to that device.
+
+### Refreshing access tokens
+
+{{% added-in v="1.3" %}}
+
+Access tokens can expire after a certain amount of time. Any HTTP calls that
+use an expired access token will return with an error code `M_UNKNOWN_TOKEN`,
+preferably with `soft_logout: true`. When a client receives this error and it
+has a refresh token, it should attempt to refresh the access token by calling
+[`/refresh`](#post_matrixclientv3refresh). Clients can also refresh their
+access token at any time, even if it has not yet expired. If the token refresh
+succeeds, the client should use the new token for future requests, and can
+re-try previously-failed requests with the new token. When an access token is
+refreshed, a new refresh token may be returned; if a new refresh token is
+given, the old refresh token will be invalidated, and the new refresh token
+should be used when the access token needs to be refreshed.
+
+The old refresh token remains valid until the new access token or refresh token
+is used, at which point the old refresh token is revoked. This ensures that if
+a client fails to receive or persist the new tokens, it will be able to repeat
+the refresh operation.
+
+If the token refresh fails and the error response included a `soft_logout:
+true` property, then the client can treat it as a [soft logout](#soft-logout)
+and attempt to obtain a new access token by re-logging in. If the error
+response does not include a `soft_logout: true` property, the client should
+consider the user as being logged out.
+
+Handling of clients that do not support refresh tokens is up to the homeserver;
+clients indicate their support for refresh tokens by including a
+`refresh_token: true` property in the request body of the
+[`/login`](#post_matrixclientv3login) and
+[`/register`](#post_matrixclientv3register) endpoints. For example, homeservers
+may allow the use of non-expiring access tokens, or may expire access tokens
+anyways and rely on soft logout behaviour on clients that don't support
+refreshing.
### Soft logout
-When a request fails due to a 401 status code per above, the server can
-include an extra response parameter, `soft_logout`, to indicate if the
-client's persisted information can be retained. This defaults to
-`false`, indicating that the server has destroyed the session. Any
+A client can be in a "soft logout" state if the server requires
+re-authentication before continuing, but does not want to invalidate the
+client's session. The server indicates that the client is in a soft logout
+state by including a `soft_logout: true` parameter in an `M_UNKNOWN_TOKEN`
+error response; the `soft_logout` parameter defaults to `false`. If the
+`soft_logout` parameter is omitted or is `false`, this means the server has
+destroyed the session and the client should not reuse it. That is, any
persisted state held by the client, such as encryption keys and device
-information, must not be reused and must be discarded.
+information, must not be reused and must be discarded. If `soft_logout` is
+`true` the client can reuse any persisted state.
-When `soft_logout` is true, the client can acquire a new access token by
-specifying the device ID it is already using to the login API. In most
-cases a `soft_logout: true` response indicates that the user's session
-has expired on the server-side and the user simply needs to provide
-their credentials again.
-
-In either case, the client's previously known access token will no
-longer function.
+{{% changed-in v="1.3" %}} A client that receives such a response can try to
+[refresh its access token](#refreshing-access-tokens), if it has a refresh
+token available. If it does not have a refresh token available, or refreshing
+fails with `soft_logout: true`, the client can acquire a new access token by
+specifying the device ID it is already using to the login API.
### User-Interactive Authentication API
@@ -1105,6 +1160,8 @@ errcode of `M_EXCLUSIVE`.
{{% http-api spec="client-server" api="login" %}}
+{{% http-api spec="client-server" api="refresh" %}}
+
{{% http-api spec="client-server" api="logout" %}}
#### Login Fallback
@@ -1741,6 +1798,16 @@ There are several APIs provided to `GET` events for a room:
### Sending events to a room
+{{% boxes/note %}}
+{{% added-in v="1.3" %}}
+
+Servers might need to post-process some events if they
+[relate to](#forming-relationships-between-events) another event. The event's
+relationship type (`rel_type`) determines any restrictions which might apply,
+such as the user only being able to send one event of a given type in relation
+to another.
+{{% /boxes/note %}}
+
{{% http-api spec="client-server" api="room_state" %}}
**Examples**
@@ -1831,6 +1898,216 @@ the topic to be removed from the room.
{{% http-api spec="client-server" api="redaction" %}}
+### Forming relationships between events
+
+{{% changed-in v="1.3" %}}
+
+In some cases it is desirable to logically associate one event's contents with
+another event's contents — for example, when replying to a message, editing an
+event, or simply looking to add context for an event's purpose.
+
+Events are related to each other in a parent/child structure, where any event can
+become a parent by simply having a child event point at it. Parent events do not
+define their children, instead relying on the children to describe their parent.
+
+The relationship between a child and its parent event is described in the child
+event's `content` as `m.relates_to` (defined below). A child event can point at
+any other event, including another child event, to build the relationship so long
+as both events are in the same room, however additional restrictions might be imposed
+by the type of the relationship (the `rel_type`).
+
+{{% boxes/note %}}
+Child events can point at other child events, forming a chain of events. These chains
+can naturally take the shape of a tree if two independent children point at a single
+parent event, for example.
+{{% /boxes/note %}}
+
+To allow the server to aggregate and find child events for a parent, the `m.relates_to`
+key of an event MUST be included in the plaintext copy of the event. It cannot be
+exclusively recorded in the encrypted payload as the server cannot decrypt the event
+for processing.
+
+{{% boxes/warning %}}
+If an encrypted event contains an `m.relates_to` in its payload, it should be
+ignored and instead favour the plaintext `m.relates_to` copy (including when there
+is no plaintext copy). This is to ensure the client's behaviour matches the server's
+capability to handle relationships.
+{{% /boxes/warning %}}
+
+Relationships which don't match the schema, or which break the rules of a relationship,
+are simply ignored. An example might be the parent and child being in different
+rooms, or the relationship missing properties required by the schema below. Clients
+handling such invalid relationships should show the events independently of each
+other, optionally with an error message.
+
+{{% boxes/note %}}
+While this specification describes an `m.relates_to` object containing a `rel_type`, there
+is not currently any relationship type which uses this structure. Replies, described below,
+form their relationship outside of the `rel_type` as a legacy type of relationship. Future
+versions of the specification might change replies to better match the relationship structures.
+
+Custom `rel_type`s can, and should, still use the schema described above for relevant
+behaviour.
+{{% /boxes/note %}}
+
+`m.relates_to` is defined as follows:
+
+{{% definition path="api/client-server/definitions/m.relates_to" %}}
+
+#### Relationship types
+
+This specification describes the following relationship types:
+
+* [Rich replies](#rich-replies) (**Note**: does not use `rel_type`).
+
+#### Aggregations
+
+{{% added-in v="1.3" %}}
+
+Some child events can be "aggregated" by the server, depending on their
+`rel_type`. This can allow a set of child events to be summarised to the client without
+the client needing the child events themselves.
+
+An example of this might be that a `rel_type` requires an extra `key` field which, when
+appropriately specified, would mean that the client receives a total count for the number
+of times that `key` was used by child events.
+
+The actual aggregation format depends on the `rel_type`.
+
+{{% boxes/note %}}
+This specification does not currently describe any `rel_type`s which require
+aggregation. This functionality forms a framework for future extensions.
+{{% /boxes/note %}}
+
+Aggregations are sometimes automatically included by a server alongside the parent
+event. This is known as a "bundled aggregation" or "bundle" for simplicity. The
+act of doing this is "bundling".
+
+When an event is served to the client through the APIs listed below, a `m.relations` property
+is included under `unsigned` if the event has child events which can be aggregated and point
+at it. The `m.relations` property is an object keyed by `rel_type` and value being the type-specific
+aggregated format for that `rel_type`, also known as the bundle.
+
+For example (unimportant fields not included):
+
+```json
+{
+ "event_id": "$my_event",
+ "unsigned": {
+ "m.relations": {
+ "org.example.possible_annotations": [
+ {
+ "key": "👍",
+ "origin_server_ts": 1562763768320,
+ "count": 3
+ },
+ {
+ "key": "👎",
+ "origin_server_ts": 1562763768320,
+ "count": 1
+ }
+ ],
+ "org.example.possible_thread": {
+ "current_server_participated": true,
+ "count": 7,
+ "latest_event": {
+ "event_id": "$another_event",
+ "content": {
+ "body": "Hello world"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+Note how the `org.example.possible_annotations` bundle is an array compared to the
+`org.example.possible_thread` bundle where the server is summarising the state of
+the relationship in a single object. Both are valid ways to aggregate, and their
+exact types depend on the `rel_type`.
+
+{{% boxes/warning %}}
+State events do not currently receive bundled aggregations. This is not
+necessarily a deliberate design decision, and MSCs which aim to fix this are welcome.
+{{% /boxes/warning %}}
+
+The endpoints where the server *should* include bundled aggregations are:
+
+* [`GET /rooms/{roomId}/messages`](#get_matrixclientv3roomsroomidmessages)
+* [`GET /rooms/{roomId}/context/{eventId}`](#get_matrixclientv3roomsroomidcontexteventid)
+* [`GET /rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid)
+* [`GET /rooms/{roomId}/relations/{eventId}`](#get_matrixclientv1roomsroomidrelationseventid)
+* [`GET /rooms/{roomId}/relations/{eventId}/{relType}`](#get_matrixclientv1roomsroomidrelationseventidreltype)
+* [`GET /rooms/{roomId}/relations/{eventId}/{relType}/{eventType}`](#get_matrixclientv1roomsroomidrelationseventidreltypeeventtype)
+* [`GET /sync`](#get_matrixclientv3sync) when the relevant section has a `limited` value
+ of `true`.
+* [`POST /search`](#post_matrixclientv3search) for any matching events under `room_events`.
+
+{{% boxes/note %}}
+The server is **not** required to return bundled aggregations on deprecated endpoints
+such as `/initialSync`.
+{{% /boxes/note %}}
+
+While this functionality allows the client to see what was known to the server at the
+time of handling, the client should continue to aggregate locally if it is aware of
+the relationship type's behaviour. For example, a client might increment a `count`
+on a parent event's bundle if it saw a new child event which referenced that parent.
+
+The bundle provided by the server only includes child events which were known at the
+time the client would receive the bundle. For example, in a single `/sync` response
+with the parent and multiple child events the child events would have already been
+included on the parent's `m.relations` field. Events received in future syncs would
+need to be aggregated manually by the client.
+
+{{% boxes/note %}}
+Events from [ignored users](#ignoring-users) do not appear in the aggregation
+from the server, however clients might still have events from ignored users cached. Like
+with normal events, clients will need to de-aggregate child events sent by ignored users to
+avoid them being considered in counts. Servers must additionally ensure they do not
+consider child events from ignored users when preparing a bundle for the client.
+{{% /boxes/note %}}
+
+When a parent event is redacted, the child events which pointed to that parent remain, however
+when a child event is redacted then the relationship is broken. Therefore, the server needs
+to de-aggregate or disassociate the event once the relationship is lost. Clients with local
+aggregation or which handle redactions locally should do the same.
+
+It is suggested that clients perform local echo on aggregations — for instance, aggregating
+a new child event into a bundle optimistically until the server returns a failure or the client
+gives up on sending the event, at which point the event should be de-aggregated and an
+error or similar shown. The client should be cautious to not aggregate an event twice if
+it has already optimistically aggregated the event. Clients are encouraged to take this
+a step further to additionally track child events which target unsent/pending events,
+likely using the transaction ID as a temporary event ID until a proper event ID is known.
+
+{{% boxes/warning %}}
+Due to history visibility restrictions, child events might not be visible to the user
+if they are in a section of history the user cannot see. This means any bundles which would
+normally include those events will be lacking them and the client will not be able to
+locally aggregate the events either — relating events of importance (such as votes) should
+take into consideration history visibility.
+
+Additionally, if the server is missing portions of the room history then it may not be
+able to accurately aggregate the events.
+{{% /boxes/warning %}}
+
+#### Relationships API
+
+{{% added-in v="1.3" %}}
+
+To retrieve the child events for a parent from the server, the client can call the
+following endpoint.
+
+This endpoint is particularly useful if the client has lost context on the aggregation for
+a parent event and needs to rebuild/verify it.
+
+{{% boxes/note %}}
+Because replies do not use `rel_type`, they will not be accessible via this API.
+{{% /boxes/note %}}
+
+{{% http-api spec="client-server" api="relations" %}}
+
## Rooms
### Types
@@ -1969,6 +2246,13 @@ room listed in the join rules. If the server cannot verify membership for any
of the listed rooms then you can only join with an invite. Note that this rule
is only expected to work in room versions [which support it](/rooms/#feature-matrix).
+{{% added-in v="1.3" %}} `knock_restricted`
+This room can be joined as though it was `restricted` *or* `knock`. If you
+interact with the room using knocking, the `knock` rule takes effect whereas
+trying to join the room without an invite applies the `restricted` join rule.
+Note that this rule is only expected to work in room versions
+[which support it](/rooms/#feature-matrix).
+
The allowable state transitions of membership are:

@@ -1984,6 +2268,15 @@ The allowable state transitions of membership are:
##### Knocking on rooms
{{% added-in v="1.1" %}}
+{{% changed-in v="1.3" %}}
+
+{{% boxes/note %}}
+As of `v1.3`, it is possible to knock on a [restricted room](#restricted-rooms)
+if the room supports and is using the `knock_restricted` join rule.
+
+Note that `knock_restricted` is only expected to work in room versions
+[which support it](/rooms/#feature-matrix).
+{{% /boxes/note %}}
-
-
- This is where the reply goes.
-
-If the related event does not have a `formatted_body`, the event's
-`body` should be considered after encoding any HTML special characters.
-Note that the `href` in both of the anchors use a [matrix.to
-URI](/appendices#matrixto-navigation).
-
-###### Stripping the fallback
-
-Clients which support rich replies MUST strip the fallback from the
-event before rendering the event. This is because the text provided in
-the fallback cannot be trusted to be an accurate representation of the
-event. After removing the fallback, clients are recommended to represent
-the event referenced by `m.in_reply_to` similar to the fallback's
-representation, although clients do have creative freedom for their user
-interface. Clients should prefer the `formatted_body` over the `body`,
-just like with other `m.room.message` events.
-
-To strip the fallback on the `body`, the client should iterate over each
-line of the string, removing any lines that start with the fallback
-prefix ("> ", including the space, without quotes) and stopping when
-a line is encountered without the prefix. This prefix is known as the
-"fallback prefix sequence".
-
-To strip the fallback on the `formatted_body`, the client should remove
-the entirety of the `mx-reply` tag.
-
-###### Fallback for `m.text`, `m.notice`, and unrecognised message types
-
-Using the prefix sequence, the first line of the related event's `body`
-should be prefixed with the user's ID, followed by each line being
-prefixed with the fallback prefix sequence. For example:
-
- > <@alice:example.org> This is the first line
- > This is the second line
-
- This is the reply
-
-The `formatted_body` uses the template defined earlier in this section.
-
-###### Fallback for `m.emote`
-
-Similar to the fallback for `m.text`, each line gets prefixed with the
-fallback prefix sequence. However an asterisk should be inserted before
-the user's ID, like so:
-
- > * <@alice:example.org> feels like today is going to be a great day
-
- This is the reply
-
-The `formatted_body` has a subtle difference for the template where the
-asterisk is also inserted ahead of the user's ID:
-
-
-
- In reply to
- * @alice:example.org
-
-
-
-
- This is where the reply goes.
-
-###### Fallback for `m.image`, `m.video`, `m.audio`, and `m.file`
-
-The related event's `body` would be a file name, which may not be very
-descriptive. The related event should additionally not have a `format`
-or `formatted_body` in the `content` - if the event does have a `format`
-and/or `formatted_body`, those fields should be ignored. Because the
-filename alone may not be descriptive, the related event's `body` should
-be considered to be `"sent a file."` such that the output looks similar
-to the following:
-
- > <@alice:example.org> sent a file.
-
- This is the reply
-
-
-
- In reply to
- @alice:example.org
-
- sent a file.
-
-
- This is where the reply goes.
-
-For `m.image`, the text should be `"sent an image."`. For `m.video`, the
-text should be `"sent a video."`. For `m.audio`, the text should be
-`"sent an audio file"`.
-
##### Spoiler messages
{{% added-in v="1.1" %}}
diff --git a/content/client-server-api/modules/rich_replies.md b/content/client-server-api/modules/rich_replies.md
new file mode 100644
index 00000000..60c02363
--- /dev/null
+++ b/content/client-server-api/modules/rich_replies.md
@@ -0,0 +1,182 @@
+---
+type: module
+---
+
+### Rich replies
+
+{{% changed-in v="1.3" %}}
+
+Rich replies are a
+special kind of [relationship](#forming-relationships-between-events) which
+effectively quotes the referenced event for the client to render/process how
+it wishes. They are normally used with [`m.room.message`](#mroommessage) events.
+
+{{% boxes/note %}}
+Until v1.3 of the spec, rich replies were limited to `m.room.message` events
+which could represent an HTML-formatted body. As of v1.3 this is now expanded
+to *all* event types by dropping the requirement that an HTML-formatted body
+be included.
+
+Additionally, a rich reply can reference any other event type as of v1.3.
+Previously, a rich reply could only reference another `m.room.message` event.
+{{% /boxes/note %}}
+
+When possible, events SHOULD include a [fallback representation](#fallbacks-for-rich-replies)
+to allow clients which do not render rich replies to still see something which
+appears to be a quoted reply.
+
+Though rich replies form a relationship to another event, they do not
+use `rel_type` to create this relationship. Instead, a subkey named `m.in_reply_to`
+is used to describe the reply's relationship, leaving the other properties of
+`m.relates_to` to describe the primary relationship of the event. This means
+that if an event is simply in reply to another event, without further relationship,
+the `rel_type` and `event_id` properties of `m.relates_to` become *optional*.
+
+An example reply would be:
+
+```json5
+{
+ "content": {
+ "m.relates_to": {
+ "m.in_reply_to": {
+ "event_id": "$another_event"
+ }
+ },
+ "body": "That sounds like a great idea!"
+ },
+ // other fields as required by events
+}
+```
+
+Note that the `event_id` of the `m.in_reply_to` object has the same requirements
+as if it were to be under `m.relates_to` directly instead.
+
+#### Fallbacks for rich replies
+
+Some clients may not have support for rich replies and therefore need a
+fallback to use instead. Clients that do not support rich replies should
+render the event as if rich replies were not special.
+
+Clients that do support rich replies SHOULD provide the fallback format on
+replies, and MUST strip the fallback before rendering the reply. The
+specific fallback text is different for each `msgtype`, however the
+general format for the `body` is:
+
+```text
+> <@alice:example.org> This is the original body
+
+This is where the reply goes
+```
+
+The `formatted_body`, if present and using an associated `format` of
+`org.matrix.custom.html`, should use the following template:
+
+```html
+
+
+ In reply to
+ @alice:example.org
+
+
+
+
+This is where the reply goes.
+```
+
+If the related event does not have a `formatted_body`, the event's
+`body` should be considered after encoding any HTML special characters.
+Note that the `href` in both of the anchors use a [matrix.to
+URI](/appendices#matrixto-navigation).
+
+##### Stripping the fallback
+
+Clients which support rich replies MUST strip the fallback from the
+event before rendering the event. This is because the text provided in
+the fallback cannot be trusted to be an accurate representation of the
+event. After removing the fallback, clients are recommended to represent
+the event referenced by `m.in_reply_to` similar to the fallback's
+representation, although clients do have creative freedom for their user
+interface. Clients should prefer the `formatted_body` over the `body`,
+just like with other `m.room.message` events.
+
+To strip the fallback on the `body`, the client should iterate over each
+line of the string, removing any lines that start with the fallback
+prefix ("> ", including the space, without quotes) and stopping when
+a line is encountered without the prefix. This prefix is known as the
+"fallback prefix sequence".
+
+To strip the fallback on the `formatted_body`, the client should remove
+the entirety of the `mx-reply` tag.
+
+##### Fallback for `m.text`, `m.notice`, and unrecognised message types
+
+Using the prefix sequence, the first line of the related event's `body`
+should be prefixed with the user's ID, followed by each line being
+prefixed with the fallback prefix sequence. For example:
+
+```text
+> <@alice:example.org> This is the first line
+> This is the second line
+
+This is the reply
+```
+
+The `formatted_body` uses the template defined earlier in this section.
+
+##### Fallback for `m.emote`
+
+Similar to the fallback for `m.text`, each line gets prefixed with the
+fallback prefix sequence. However an asterisk should be inserted before
+the user's ID, like so:
+
+```text
+> * <@alice:example.org> feels like today is going to be a great day
+
+This is the reply
+```
+
+The `formatted_body` has a subtle difference for the template where the
+asterisk is also inserted ahead of the user's ID:
+
+```html
+
+
+ In reply to
+ * @alice:example.org
+
+
+
+
+This is where the reply goes.
+```
+
+##### Fallback for `m.image`, `m.video`, `m.audio`, and `m.file`
+
+The related event's `body` would be a file name, which may not be very
+descriptive. The related event should additionally not have a `format`
+or `formatted_body` in the `content` - if the event does have a `format`
+and/or `formatted_body`, those fields should be ignored. Because the
+filename alone may not be descriptive, the related event's `body` should
+be considered to be `"sent a file."` such that the output looks similar
+to the following:
+
+```text
+> <@alice:example.org> sent a file.
+
+This is the reply
+```
+```html
+
+
+ In reply to
+ @alice:example.org
+
+ sent a file.
+
+
+This is where the reply goes.
+```
+
+For `m.image`, the text should be `"sent an image."`. For `m.video`, the
+text should be `"sent a video."`. For `m.audio`, the text should be
+`"sent an audio file"`.
\ No newline at end of file
diff --git a/content/rooms/_index.md b/content/rooms/_index.md
index f946cb61..ac93e69e 100644
--- a/content/rooms/_index.md
+++ b/content/rooms/_index.md
@@ -36,10 +36,11 @@ Alternatively, consider flipping the column/row organization to be features
up top and versions on the left.
-->
-| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
-|-------------------|---|---|---|---|---|---|---|---|---|
-| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ |
-| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ |
+| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
+|-------------------|---|---|---|---|---|---|---|---|---|----|
+| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ |
+| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ |
+| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ |
## Complete list of room versions
@@ -73,6 +74,8 @@ The available room versions are:
of another room to join without invite.
- [Version 9](/rooms/v9) - **Stable**. Builds on v8 to fix issues when
redacting some membership events.
+- [Version 10](/rooms/v10) - **Stable**. Enforces integer-only power levels
+ and adds `knock_restricted` join rule.
## Room version grammar
diff --git a/content/rooms/fragments/v1-deprecated-formatting-off-spec.md b/content/rooms/fragments/v1-deprecated-formatting-off-spec.md
new file mode 100644
index 00000000..1cf7d49f
--- /dev/null
+++ b/content/rooms/fragments/v1-deprecated-formatting-off-spec.md
@@ -0,0 +1,13 @@
+---
+toc_hide: true
+---
+
+Events sent into rooms of this version can have formats which are different
+from their normal schema. Those cases are documented here.
+
+{{% boxes/warning %}}
+The behaviour described here is preserved strictly for backwards compatibility
+only. A homeserver should take reasonable precautions to prevent users from
+sending these so-called "malformed" events, and must never rely on the behaviours
+described here as a default.
+{{% /boxes/warning %}}
diff --git a/content/rooms/fragments/v1-stringy-power-levels.md b/content/rooms/fragments/v1-stringy-power-levels.md
new file mode 100644
index 00000000..054c0506
--- /dev/null
+++ b/content/rooms/fragments/v1-stringy-power-levels.md
@@ -0,0 +1,43 @@
+---
+toc_hide: true
+---
+
+##### `m.room.power_levels` events accept values as strings
+
+In order to maintain backwards compatibility with early implementations,
+each of the integer-valued properties within
+[`m.room.power_levels`](/client-server-api#mroompower_levels) events can
+be encoded as strings instead of integers. This includes the nested values
+within the `events`, `notifications` and `users` properties.
+For example, the following is a valid `m.room.power_levels` event in this room version:
+
+```json
+{
+ "content": {
+ "ban": "50",
+ "events": {
+ "m.room.power_levels": "100"
+ },
+ "events_default": "0",
+ "state_default": "50",
+ "users": {
+ "@example:localhost": "100"
+ },
+ "users_default": "0"
+ },
+ "origin_server_ts": 1432735824653,
+ "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
+ "sender": "@example:example.org",
+ "state_key": "",
+ "type": "m.room.power_levels"
+}
+```
+
+When the value is representative of an integer, they must be the following format:
+
+* a single base 10 integer, no float values or decimal points, optionally with
+ any number of leading zeroes (`"100"`, `"000100"`);
+* optionally prefixed with a single `-` or `+` character before the integer (`"+100"`,
+ `"-100"`).
+* optionally with any number of leading or trailing whitespace characters (`" 100 "`,
+ `" 00100 "`, `" +100 "`, `" -100 "`);
diff --git a/content/rooms/fragments/v9-redactions.md b/content/rooms/fragments/v9-redactions.md
new file mode 100644
index 00000000..3247c59f
--- /dev/null
+++ b/content/rooms/fragments/v9-redactions.md
@@ -0,0 +1,51 @@
+---
+toc_hide: true
+---
+
+{{% added-in this=true %}} `m.room.member` events now keep `join_authorised_via_users_server`
+in addition to other keys in `content` when being redacted.
+
+{{% boxes/rationale %}}
+Without the `join_authorised_via_users_server` property, redacted join events
+can become invalid when verifying the auth chain of a given event, thus creating
+a split-brain scenario where the user is able to speak from one server's
+perspective but most others will continually reject their events.
+
+This can theoretically be worked around with a rejoin to the room, being careful
+not to use the faulty events as `prev_events`, though instead it is encouraged
+to use v9 rooms over v8 rooms to outright avoid the situation.
+
+[Issue #3373](https://github.com/matrix-org/matrix-doc/issues/3373) has further
+information.
+{{% /boxes/rationale %}}
+
+The full redaction algorithm follows.
+
+Upon receipt of a redaction event, the server must strip off any keys
+not in the following list:
+
+- `event_id`
+- `type`
+- `room_id`
+- `sender`
+- `state_key`
+- `content`
+- `hashes`
+- `signatures`
+- `depth`
+- `prev_events`
+- `prev_state`
+- `auth_events`
+- `origin`
+- `origin_server_ts`
+- `membership`
+
+The content object must also be stripped of all keys, unless it is one
+of one of the following event types:
+
+- `m.room.member` allows keys `membership`, `join_authorised_via_users_server`.
+- `m.room.create` allows key `creator`.
+- `m.room.join_rules` allows keys `join_rule`, `allow`.
+- `m.room.power_levels` allows keys `ban`, `events`, `events_default`,
+ `kick`, `redact`, `state_default`, `users`, `users_default`.
+- `m.room.history_visibility` allows key `history_visibility`.
\ No newline at end of file
diff --git a/content/rooms/v1.md b/content/rooms/v1.md
index a69e3d5d..3d3e9738 100644
--- a/content/rooms/v1.md
+++ b/content/rooms/v1.md
@@ -48,6 +48,12 @@ Events in version 1 rooms have the following structure:
{{% definition path="api/server-server/definitions/pdu" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### Authorization rules
{{% rver-fragment name="v1-auth-rules" %}}
diff --git a/content/rooms/v10.md b/content/rooms/v10.md
new file mode 100644
index 00000000..63a2e529
--- /dev/null
+++ b/content/rooms/v10.md
@@ -0,0 +1,277 @@
+---
+title: Room Version 10
+type: docs
+weight: 100
+---
+
+This room version builds on [version 9](/rooms/v9) to enforce that power level
+values be integers, and to introduce a new `knock_restricted` join rule, allowing
+prospective members to more easily join such a room.
+
+## Client considerations
+
+This room version adds a new `knock_restricted` join rule to allow prospective
+members of a room join either through knocking (introduced in [room version 7](/rooms/v7))
+or through "join restrictions" (introduced in [room version 8](/rooms/v8) and
+refined in [room version 9](/rooms/v9)).
+
+Clients should render the new join rule accordingly for such rooms. For example:
+
+```
+This room is:
+[ ] Public
+[x] Private
+
+Join rules (disabled when Public):
+[x] Allow members of `#space:example.org` to join
+[x] Allow knocking
+```
+
+Clients which implement the redaction algorithm locally should refer to the
+[redactions](#redactions) section below for a full overview.
+
+## Server implementation components
+
+{{% boxes/warning %}}
+The information contained in this section is strictly for server
+implementors. Applications which use the Client-Server API are generally
+unaffected by the intricacies contained here. The section above
+regarding client considerations is the resource that Client-Server API
+use cases should reference.
+{{% /boxes/warning %}}
+
+[Room version 7](/rooms/v7) added "knocking" and [room version 8](/rooms/v8)
+added "join restrictions" (refined by [room version 9](/rooms/v9)) — both allow
+prospective members an avenue to join, however it was not possible to use
+the two mechanisms together. This room version adds a new
+`knock_restricted` join rule as a mix of the two behaviours, allowing a user to
+join the room if they meet either the `restricted` join rule criteria or the
+`knock` join rule criteria.
+
+This room version additionally requires that values in the power levels event
+be integers and not string representations, unlike other room versions.
+
+Room version 10 is based upon room version 9 with the following considerations.
+
+### Event format
+
+The event format is unchanged by this room version. See [below](#event-format-1)
+for details on the current event format.
+
+#### Deprecated event content schemas
+
+While this room version does not change the event format specifically, some
+deprecated behaviours are strictly no longer supported.
+
+##### Values in `m.room.power_levels` events must be integers
+
+In other room versions, such as [v9](/rooms/v9/#mroompower_levels-events-accept-values-as-strings),
+power levels could be represented as strings for backwards compatibility.
+
+This backwards compatibility is removed in this room version - power levels MUST NOT
+be represented as strings within this room version. Power levels which are not
+correctly structured are rejected under the authorization rules below.
+
+### Authorization rules
+
+Events must be signed by the server denoted by the `sender` key.
+
+`m.room.redaction` events are not explicitly part of the auth rules.
+They are still subject to the minimum power level rules, but should always
+fall into "10. Otherwise, allow". Instead of being authorized at the time
+of receipt, they are authorized at a later stage: see the
+[Redactions](#redactions) section below for more information.
+
+The types of state events that affect authorization are:
+
+- [`m.room.create`](/client-server-api#mroomcreate)
+- [`m.room.member`](/client-server-api#mroommember)
+- [`m.room.join_rules`](/client-server-api#mroom)
+- [`m.room.power_levels`](/client-server-api#mroompower_levels)
+- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite)
+
+{{% boxes/note %}}
+Power levels are inferred from defaults when not explicitly supplied.
+For example, mentions of the `sender`'s power level can also refer to
+the default power level for users in the room.
+{{% /boxes/note %}}
+
+The rules are as follows:
+
+1. If type is `m.room.create`:
+ 1. If it has any previous events, reject.
+ 2. If the domain of the `room_id` does not match the domain of the
+ `sender`, reject.
+ 3. If `content.room_version` is present and is not a recognised
+ version, reject.
+ 4. If `content` has no `creator` field, reject.
+ 5. Otherwise, allow.
+2. Reject if event has `auth_events` that:
+ 1. have duplicate entries for a given `type` and `state_key` pair
+ 2. have entries whose `type` and `state_key` don't match those
+ specified by the [auth events
+ selection](/server-server-api#auth-events-selection)
+ algorithm described in the server specification.
+3. If event does not have a `m.room.create` in its `auth_events`,
+ reject.
+4. If type is `m.room.member`:
+ 1. If no `state_key` key or `membership` key in `content`, reject.
+ 2. If `content` has a `join_authorised_via_users_server`
+ key:
+ 1. If the event is not validly signed by the homeserver of the user ID denoted
+ by the key, reject.
+ 3. If `membership` is `join`:
+ 1. If the only previous event is an `m.room.create` and the
+ `state_key` is the creator, allow.
+ 2. If the `sender` does not match `state_key`, reject.
+ 3. If the `sender` is banned, reject.
+ 4. If the `join_rule` is `invite` or `knock` then allow if
+ membership state is `invite` or `join`.
+ 5. {{< changed-in this="true" >}}
+ If the `join_rule` is `restricted` or `knock_restricted`:
+ 1. If membership state is `join` or `invite`, allow.
+ 2. If the `join_authorised_via_users_server` key in `content`
+ is not a user with sufficient permission to invite other
+ users, reject.
+ 3. Otherwise, allow.
+ 6. If the `join_rule` is `public`, allow.
+ 7. Otherwise, reject.
+ 4. If `membership` is `invite`:
+ 1. If `content` has `third_party_invite` key:
+ 1. If *target user* is banned, reject.
+ 2. If `content.third_party_invite` does not have a `signed`
+ key, reject.
+ 3. If `signed` does not have `mxid` and `token` keys,
+ reject.
+ 4. If `mxid` does not match `state_key`, reject.
+ 5. If there is no `m.room.third_party_invite` event in the
+ current room state with `state_key` matching `token`,
+ reject.
+ 6. If `sender` does not match `sender` of the
+ `m.room.third_party_invite`, reject.
+ 7. If any signature in `signed` matches any public key in
+ the `m.room.third_party_invite` event, allow. The public
+ keys are in `content` of `m.room.third_party_invite` as:
+ 1. A single public key in the `public_key` field.
+ 2. A list of public keys in the `public_keys` field.
+ 8. Otherwise, reject.
+ 2. If the `sender`'s current membership state is not `join`,
+ reject.
+ 3. If *target user*'s current membership state is `join` or
+ `ban`, reject.
+ 4. If the `sender`'s power level is greater than or equal to
+ the *invite level*, allow.
+ 5. Otherwise, reject.
+ 5. If `membership` is `leave`:
+ 1. If the `sender` matches `state_key`, allow if and only if
+ that user's current membership state is `invite`, `join`,
+ or `knock`.
+ 2. If the `sender`'s current membership state is not `join`,
+ reject.
+ 3. If the *target user*'s current membership state is `ban`,
+ and the `sender`'s power level is less than the *ban level*,
+ reject.
+ 4. If the `sender`'s power level is greater than or equal to
+ the *kick level*, and the *target user*'s power level is
+ less than the `sender`'s power level, allow.
+ 5. Otherwise, reject.
+ 6. If `membership` is `ban`:
+ 1. If the `sender`'s current membership state is not `join`,
+ reject.
+ 2. If the `sender`'s power level is greater than or equal to
+ the *ban level*, and the *target user*'s power level is less
+ than the `sender`'s power level, allow.
+ 3. Otherwise, reject.
+ 7. If `membership` is `knock`:
+ 1. {{< changed-in this="true" >}}
+ If the `join_rule` is anything other than `knock` or
+ `knock_restricted`, reject.
+ 2. If `sender` does not match `state_key`, reject.
+ 3. If the `sender`'s current membership is not `ban`, `invite`,
+ or `join`, allow.
+ 4. Otherwise, reject.
+ 8. Otherwise, the membership is unknown. Reject.
+5. If the `sender`'s current membership state is not `join`, reject.
+6. If type is `m.room.third_party_invite`:
+ 1. Allow if and only if `sender`'s current power level is greater
+ than or equal to the *invite level*.
+7. If the event type's *required power level* is greater than the
+ `sender`'s power level, reject.
+8. If the event has a `state_key` that starts with an `@` and does not
+ match the `sender`, reject.
+9. If type is `m.room.power_levels`:
+ 1. {{< added-in this="true" >}}
+ If any of the keys `users_default`, `events_default`, `state_default`,
+ `ban`, `redact`, `kick`, or `invite` in `content` are present and
+ not an integer, reject.
+ 2. {{< added-in this="true" >}}
+ If either of the keys `events` or `notifications` in `content`
+ are present and not a dictionary with values that are integers,
+ reject.
+ 3. If `users` key in `content` is not a dictionary with keys that
+ are valid user IDs with values that are integers, reject.
+ 2. If there is no previous `m.room.power_levels` event in the room,
+ allow.
+ 3. For the keys `users_default`, `events_default`, `state_default`,
+ `ban`, `redact`, `kick`, `invite` check if they were added,
+ changed or removed. For each found alteration:
+ 1. If the current value is higher than the `sender`'s current
+ power level, reject.
+ 2. If the new value is higher than the `sender`'s current power
+ level, reject.
+ 4. For each entry being added, changed or removed in both the
+ `events`, `users`, and `notifications` keys:
+ 1. If the current value is higher than the `sender`'s current
+ power level, reject.
+ 2. If the new value is higher than the `sender`'s current power
+ level, reject.
+ 5. For each entry being changed under the `users` key, other than
+ the `sender`'s own entry:
+ 1. If the current value is equal to the `sender`'s current
+ power level, reject.
+ 6. Otherwise, allow.
+10. Otherwise, allow.
+
+{{% boxes/note %}}
+Some consequences of these rules:
+
+- Unless you are a member of the room, the only permitted operations
+ (apart from the initial create/join) are: joining a public room;
+ accepting or rejecting an invitation to a room.
+- To unban somebody, you must have power level greater than or equal
+ to both the kick *and* ban levels, *and* greater than the target
+ user's power level.
+{{% /boxes/note %}}
+
+## Unchanged from v9
+
+The following sections have not been modified since v9, but are included for
+completeness.
+
+### Redactions
+
+{{% rver-fragment name="v9-redactions" %}}
+
+### Handling redactions
+
+{{% rver-fragment name="v3-handling-redactions" %}}
+
+### Event IDs
+
+{{% rver-fragment name="v4-event-ids" %}}
+
+### Event format
+
+{{% rver-fragment name="v4-event-format" %}}
+
+### State resolution
+
+{{% rver-fragment name="v2-state-res" %}}
+
+### Canonical JSON
+
+{{% rver-fragment name="v6-canonical-json" %}}
+
+### Signing key validity period
+
+{{% rver-fragment name="v5-signing-requirements" %}}
diff --git a/content/rooms/v2.md b/content/rooms/v2.md
index cdc59190..274e0ea0 100644
--- a/content/rooms/v2.md
+++ b/content/rooms/v2.md
@@ -46,6 +46,12 @@ Events in rooms of this version have the following structure:
{{% definition path="api/server-server/definitions/pdu" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### Authorization rules
{{% rver-fragment name="v1-auth-rules" %}}
diff --git a/content/rooms/v3.md b/content/rooms/v3.md
index 310c6625..8dd261e8 100644
--- a/content/rooms/v3.md
+++ b/content/rooms/v3.md
@@ -81,6 +81,12 @@ The complete structure of a event in a v3 room is shown below.
{{% definition path="api/server-server/definitions/pdu_v3" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### Authorization rules
{{% added-in this=true %}} `m.room.redaction` events are no longer
diff --git a/content/rooms/v4.md b/content/rooms/v4.md
index 01c695ba..c329f342 100644
--- a/content/rooms/v4.md
+++ b/content/rooms/v4.md
@@ -69,6 +69,12 @@ the changes in this room version.
{{% rver-fragment name="v4-event-format" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### Authorization rules
{{% rver-fragment name="v3-auth-rules" %}}
diff --git a/content/rooms/v5.md b/content/rooms/v5.md
index b4283071..25147e9e 100644
--- a/content/rooms/v5.md
+++ b/content/rooms/v5.md
@@ -51,6 +51,12 @@ completeness.
{{% rver-fragment name="v4-event-format" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### Authorization rules
{{% rver-fragment name="v3-auth-rules" %}}
diff --git a/content/rooms/v6.md b/content/rooms/v6.md
index cb87082c..0e2e70dc 100644
--- a/content/rooms/v6.md
+++ b/content/rooms/v6.md
@@ -212,6 +212,12 @@ completeness.
{{% rver-fragment name="v4-event-format" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### State resolution
{{% rver-fragment name="v2-state-res" %}}
diff --git a/content/rooms/v7.md b/content/rooms/v7.md
index 2ada06f7..5960c198 100644
--- a/content/rooms/v7.md
+++ b/content/rooms/v7.md
@@ -1,7 +1,7 @@
---
title: Room Version 7
type: docs
-weight: 60
+weight: 70
---
This room version builds on [version 6](/rooms/v6) to introduce knocking
@@ -205,6 +205,12 @@ completeness.
{{% rver-fragment name="v4-event-format" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### State resolution
{{% rver-fragment name="v2-state-res" %}}
diff --git a/content/rooms/v8.md b/content/rooms/v8.md
index 50a1f065..2a8cf125 100644
--- a/content/rooms/v8.md
+++ b/content/rooms/v8.md
@@ -1,7 +1,7 @@
---
title: Room Version 8
type: docs
-weight: 60
+weight: 80
---
This room version builds on [version 7](/rooms/v7) to introduce a new
@@ -110,6 +110,12 @@ completeness.
{{% rver-fragment name="v4-event-format" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### State resolution
{{% rver-fragment name="v2-state-res" %}}
diff --git a/content/rooms/v9.md b/content/rooms/v9.md
index 285a7640..d4da72de 100644
--- a/content/rooms/v9.md
+++ b/content/rooms/v9.md
@@ -1,7 +1,7 @@
---
title: Room Version 9
type: docs
-weight: 60
+weight: 90
---
This room version builds on [version 8](/rooms/v8) to add additional redaction
@@ -17,55 +17,7 @@ Clients which implement the redaction algorithm locally should refer to the
### Redactions
-{{% added-in this=true %}} `m.room.member` now keep `join_authorised_via_users_server`
-in addition to other keys in `content` when being redacted.
-
-{{% boxes/rationale %}}
-Without the `join_authorised_via_users_server` property, redacted join events
-can become invalid when verifying the auth chain of a given event, thus creating
-a split-brain scenario where the user is able to speak from one server's
-perspective but most others will continually reject their events.
-
-This can theoretically be worked around with a rejoin to the room, being careful
-not to use the faulty events as `prev_events`, though instead it is encouraged
-to use v9 rooms over v8 rooms to outright avoid the situation.
-
-[Issue #3373](https://github.com/matrix-org/matrix-doc/issues/3373) has further
-information.
-{{% /boxes/rationale %}}
-
-The full redaction algorithm follows.
-
-{{% rver-fragment name="v3-handling-redactions" %}}
-
-Upon receipt of a redaction event, the server must strip off any keys
-not in the following list:
-
-- `event_id`
-- `type`
-- `room_id`
-- `sender`
-- `state_key`
-- `content`
-- `hashes`
-- `signatures`
-- `depth`
-- `prev_events`
-- `prev_state`
-- `auth_events`
-- `origin`
-- `origin_server_ts`
-- `membership`
-
-The content object must also be stripped of all keys, unless it is one
-of one of the following event types:
-
-- `m.room.member` allows keys `membership`, `join_authorised_via_users_server`.
-- `m.room.create` allows key `creator`.
-- `m.room.join_rules` allows keys `join_rule`, `allow`.
-- `m.room.power_levels` allows keys `ban`, `events`, `events_default`,
- `kick`, `redact`, `state_default`, `users`, `users_default`.
-- `m.room.history_visibility` allows key `history_visibility`.
+{{% rver-fragment name="v9-redactions" withVersioning="true" %}}
## Server implementation components
@@ -102,6 +54,12 @@ completeness.
{{% rver-fragment name="v4-event-format" %}}
+#### Deprecated event content schemas
+
+{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}}
+
+{{% rver-fragment name="v1-stringy-power-levels" %}}
+
### Authorization rules
{{% rver-fragment name="v8-auth-rules" %}}
diff --git a/content/server-server-api.md b/content/server-server-api.md
index f70e8994..12d4bc45 100644
--- a/content/server-server-api.md
+++ b/content/server-server-api.md
@@ -432,6 +432,16 @@ unspecified.
For an `m.room.member` state event, the user given by the `state_key` of
the event.
+{{% boxes/warning %}}
+Some [room versions](/rooms) accept power level values to be represented as
+strings rather than integers. This is strictly for backwards compatibility.
+A homeserver should take reasonable precautions to prevent users from sending
+new power level events with string values (eg: by rejecting the API request),
+and must never populate the default power levels in a room as string values.
+
+See the [room version specification](/rooms) for more information.
+{{% /boxes/warning %}}
+
#### Authorization rules
The rules governing whether an event is authorized depends on a set of
diff --git a/data/api/client-server/definitions/auth_data.yaml b/data/api/client-server/definitions/auth_data.yaml
index 4bfbf62b..691cdc65 100644
--- a/data/api/client-server/definitions/auth_data.yaml
+++ b/data/api/client-server/definitions/auth_data.yaml
@@ -28,7 +28,6 @@ properties:
type: string
additionalProperties:
description: Keys dependent on the login type
- type: object
example:
type: "example.type.foo"
session: "xxxxx"
diff --git a/data/api/client-server/definitions/client_event_without_room_id.yaml b/data/api/client-server/definitions/client_event_without_room_id.yaml
index 1b6d6073..c4db8b0e 100644
--- a/data/api/client-server/definitions/client_event_without_room_id.yaml
+++ b/data/api/client-server/definitions/client_event_without_room_id.yaml
@@ -38,6 +38,10 @@ properties:
Present if, and only if, this event is a *state* event. The key making
this piece of state unique in the room. Note that it is often an empty
string.
+
+ State keys starting with an `@` are reserved for referencing user IDs, such
+ as room members. With the exception of a few events, state events set with a
+ given user's ID as the state key MUST only be set by that user.
type: string
example: '@user:example.org'
sender:
diff --git a/data/api/client-server/definitions/m.relates_to.yaml b/data/api/client-server/definitions/m.relates_to.yaml
new file mode 100644
index 00000000..591281c3
--- /dev/null
+++ b/data/api/client-server/definitions/m.relates_to.yaml
@@ -0,0 +1,43 @@
+# Copyright 2022 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+type: object
+title: m.relates_to
+description: |-
+ Describes the relationship of an event to its parent. This is contained
+ within the event's `content` alongside other fields for the relevant event type.
+example: {
+ # We deliberately "break" the example by including the top-level field so it renders
+ # sensibly for readers of the spec.
+ "m.relates_to": {
+ "rel_type": "org.example.relationship",
+ "event_id": "$an_event"
+ }
+}
+properties:
+ rel_type:
+ type: string
+ description: |-
+ The namespaced relationship type. Values must use the
+ [Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar).
+
+ The relationship type determines how clients should perceive the event, and in what
+ context. Some relationship types are processed server-side for "bundling", though not
+ all relationships require such behaviour. For example, an `m.thread` relationship type
+ might denote that the event is part of a "thread" of messages and should be rendered as
+ such.
+ event_id:
+ type: string
+ description: The event ID of the event that this event relates to.
+required: ['rel_type', 'event_id']
diff --git a/data/api/client-server/login.yaml b/data/api/client-server/login.yaml
index 8865665f..d279445d 100644
--- a/data/api/client-server/login.yaml
+++ b/data/api/client-server/login.yaml
@@ -1,5 +1,6 @@
# Copyright 2016 OpenMarket Ltd
# Copyright 2018 New Vector Ltd
+# Copyright 2022 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -133,6 +134,11 @@ paths:
description: |-
A display name to assign to the newly-created device. Ignored
if `device_id` corresponds to a known device.
+ refresh_token:
+ type: boolean
+ description: |-
+ If true, the client supports refresh tokens.
+ x-addedInMatrixVersion: "1.3"
required: ["type"]
responses:
@@ -142,6 +148,8 @@ paths:
application/json: {
"user_id": "@cheeky_monkey:matrix.org",
"access_token": "abc123",
+ "refresh_token": "def456",
+ "expires_in_ms": 60000,
"device_id": "GHTYAJCE",
"well_known": {
"m.homeserver": {
@@ -163,6 +171,23 @@ paths:
description: |-
An access token for the account.
This access token can then be used to authorize other requests.
+ refresh_token:
+ type: string
+ description: |-
+ A refresh token for the account. This token can be used to
+ obtain a new access token when it expires by calling the
+ `/refresh` endpoint.
+ x-addedInMatrixVersion: "1.3"
+ expires_in_ms:
+ type: integer
+ description: |-
+ The lifetime of the access token, in milliseconds. Once
+ the access token has expired a new access token can be
+ obtained by using the provided refresh token. If no
+ refresh token is provided, the client will need to re-log in
+ to obtain a new access token. If not given, the client can
+ assume that the access token will not expire.
+ x-addedInMatrixVersion: "1.3"
home_server:
type: string
description: |-
diff --git a/data/api/client-server/refresh.yaml b/data/api/client-server/refresh.yaml
new file mode 100644
index 00000000..da34070c
--- /dev/null
+++ b/data/api/client-server/refresh.yaml
@@ -0,0 +1,108 @@
+# Copyright 2022 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+swagger: '2.0'
+info:
+ title: "Matrix Client-Server Registration and Login API"
+ version: "1.0.0"
+host: localhost:8008
+schemes:
+ - https
+ - http
+basePath: /_matrix/client/v3
+consumes:
+ - application/json
+produces:
+ - application/json
+paths:
+ "/refresh":
+ post:
+ x-addedInMatrixVersion: "1.3"
+ summary: Refresh an access token
+ description: |-
+ Refresh an access token. Clients should use the returned access token
+ when making subsequent API calls, and store the returned refresh token
+ (if given) in order to refresh the new access token when necessary.
+
+ After an access token has been refreshed, a server can choose to
+ invalidate the old access token immediately, or can choose not to, for
+ example if the access token would expire soon anyways. Clients should
+ not make any assumptions about the old access token still being valid,
+ and should use the newly provided access token instead.
+
+ The old refresh token remains valid until the new access token or refresh token
+ is used, at which point the old refresh token is revoked.
+
+ Note that this endpoint does not require authentication via an
+ access token. Authentication is provided via the refresh token.
+
+ Application Service identity assertion is disabled for this endpoint.
+ operationId: refresh
+ parameters:
+ - in: body
+ name: body
+ required: true
+ schema:
+ type: object
+ example: {
+ "refresh_token": "some_token"
+ }
+ properties:
+ refresh_token:
+ type: string
+ description: The refresh token
+ responses:
+ 200:
+ description: A new access token and refresh token were generated.
+ examples:
+ application/json: {
+ "access_token": "a_new_token",
+ "expires_in_ms": 60000,
+ "refresh_token": "another_new_token"
+ }
+ schema:
+ type: object
+ properties:
+ access_token:
+ type: string
+ description: |-
+ The new access token to use.
+ refresh_token:
+ type: string
+ description: |-
+ The new refresh token to use when the access token needs to
+ be refreshed again. If not given, the old refresh token can
+ be re-used.
+ expires_in_ms:
+ type: integer
+ description: |-
+ The lifetime of the access token, in milliseconds. If not
+ given, the client can assume that the access token will not
+ expire.
+ required:
+ - access_token
+ 401:
+ description: |-
+ The provided token was unknown, or has already been used.
+ examples:
+ application/json: {
+ "errcode": "M_UNKNOWN_TOKEN",
+ "error": "Soft logged out",
+ "soft_logout": true
+ }
+ schema:
+ "$ref": "definitions/errors/error.yaml"
+ 429:
+ description: This request was rate-limited.
+ schema:
+ "$ref": "definitions/errors/rate_limited.yaml"
diff --git a/data/api/client-server/registration.yaml b/data/api/client-server/registration.yaml
index 810d8bc9..f48385e9 100644
--- a/data/api/client-server/registration.yaml
+++ b/data/api/client-server/registration.yaml
@@ -1,4 +1,5 @@
# Copyright 2016 OpenMarket Ltd
+# Copyright 2022 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -127,6 +128,11 @@ paths:
returned from this call, therefore preventing an automatic
login. Defaults to false.
example: false
+ refresh_token:
+ type: boolean
+ description: |-
+ If true, the client supports refresh tokens.
+ x-addedInMatrixVersion: "1.3"
responses:
200:
description: The account has been registered.
@@ -152,6 +158,27 @@ paths:
An access token for the account.
This access token can then be used to authorize other requests.
Required if the `inhibit_login` option is false.
+ refresh_token:
+ type: string
+ description: |-
+ A refresh token for the account. This token can be used to
+ obtain a new access token when it expires by calling the
+ `/refresh` endpoint.
+
+ Omitted if the `inhibit_login` option is true.
+ x-addedInMatrixVersion: "1.3"
+ expires_in_ms:
+ type: integer
+ description: |-
+ The lifetime of the access token, in milliseconds. Once
+ the access token has expired a new access token can be
+ obtained by using the provided refresh token. If no
+ refresh token is provided, the client will need to re-log in
+ to obtain a new access token. If not given, the client can
+ assume that the access token will not expire.
+
+ Omitted if the `inhibit_login` option is true.
+ x-addedInMatrixVersion: "1.3"
home_server:
type: string
description: |-
diff --git a/data/api/client-server/relations.yaml b/data/api/client-server/relations.yaml
new file mode 100644
index 00000000..dc0d8761
--- /dev/null
+++ b/data/api/client-server/relations.yaml
@@ -0,0 +1,425 @@
+# Copyright 2022 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+swagger: '2.0'
+info:
+ title: "Matrix Client-Server Relations API"
+ version: "1.0.0"
+host: localhost:8008
+schemes:
+ - https
+ - http
+basePath: /_matrix/client/v1
+consumes:
+ - application/json
+produces:
+ - application/json
+securityDefinitions:
+ $ref: definitions/security.yaml
+paths:
+ "/rooms/{roomId}/relations/{eventId}":
+ get:
+ summary: Get the child events for a given parent event.
+ description: |-
+ Retrieve all of the child events for a given parent event.
+
+ Note that when paginating the `from` token should be "after" the `to` token in
+ terms of topological ordering, because it is only possible to paginate "backwards"
+ through events, starting at `from`.
+
+ For example, passing a `from` token from page 2 of the results, and a `to` token
+ from page 1, would return the empty set. The caller can use a `from` token from
+ page 1 and a `to` token from page 2 to paginate over the same range, however.
+ operationId: getRelatingEvents
+ security:
+ - accessToken: []
+ parameters:
+ - in: path
+ type: string
+ name: roomId
+ description: The ID of the room containing the parent event.
+ required: true
+ x-example: "!636q39766251:matrix.org"
+ - in: path
+ type: string
+ name: eventId
+ description: The ID of the parent event whose child events are to be returned.
+ required: true
+ x-example: "$asfDuShaf7Gafaw"
+ - in: query
+ type: string
+ name: from
+ description: |-
+ The pagination token to start returning results from. If not supplied, results
+ start at the most recent topological event known to the server.
+
+ Can be a `next_batch` token from a previous call, or a returned
+ `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages),
+ or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync).
+ required: false
+ x-example: "page2_token"
+ - in: query
+ type: string
+ name: to
+ description: |-
+ The pagination token to stop returning results at. If not supplied, results
+ continue up to `limit` or until there are no more events.
+
+ Like `from`, this can be a previous token from a prior call to this endpoint
+ or from `/messages` or `/sync`.
+ required: false
+ x-example: "page3_token"
+ - in: query
+ type: integer
+ name: limit
+ description: |-
+ The maximum number of results to return in a single `chunk`. The server can
+ and should apply a maximum value to this parameter to avoid large responses.
+
+ Similarly, the server should apply a default value when not supplied.
+ required: false
+ x-example: 20
+ responses:
+ # note: this endpoint deliberately does not support rate limiting, therefore a
+ # 429 error response is not included.
+
+ 200:
+ description: |-
+ The paginated child events which point to the parent. If no events are
+ pointing to the parent or the pagination yields no results, an empty `chunk`
+ is returned.
+ examples:
+ application/json: {
+ "chunk": [{
+ "room_id": "!636q39766251:matrix.org",
+ "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml",
+ "content": {
+ "m.relates_to": {
+ "rel_type": "org.example.my_relation",
+ "event_id": "$asfDuShaf7Gafaw"
+ }
+ }
+ }],
+ "next_batch": "page2_token",
+ "prev_batch": "page1_token"
+ }
+ schema:
+ type: object
+ properties:
+ chunk:
+ title: "ChildEventsChunk"
+ type: array
+ description: |-
+ The child events of the requested event, ordered topologically most-recent first.
+ items:
+ allOf:
+ - "$ref": "definitions/client_event.yaml"
+ next_batch:
+ type: string
+ description: |-
+ An opaque string representing a pagination token. The absence of this token
+ means there are no more results to fetch and the client should stop paginating.
+ prev_batch:
+ type: string
+ description: |-
+ An opaque string representing a pagination token. The absence of this token
+ means this is the start of the result set, i.e. this is the first batch/page.
+ required: ['chunk']
+ 404:
+ description: |-
+ The parent event was not found or the user does not have permission to read
+ this event (it might be contained in history that is not accessible to the user).
+ examples:
+ application/json: {
+ "errcode": "M_NOT_FOUND",
+ "error": "Event not found."
+ }
+ schema:
+ "$ref": "definitions/errors/error.yaml"
+ tags:
+ - Event relationships
+ # The same as above, with added `/{relType}`
+ "/rooms/{roomId}/relations/{eventId}/{relType}":
+ get:
+ summary: Get the child events for a given parent event, with a given `relType`.
+ description: |-
+ Retrieve all of the child events for a given parent event which relate to the parent
+ using the given `relType`.
+
+ Note that when paginating the `from` token should be "after" the `to` token in
+ terms of topological ordering, because it is only possible to paginate "backwards"
+ through events, starting at `from`.
+
+ For example, passing a `from` token from page 2 of the results, and a `to` token
+ from page 1, would return the empty set. The caller can use a `from` token from
+ page 1 and a `to` token from page 2 to paginate over the same range, however.
+ operationId: getRelatingEventsWithRelType
+ security:
+ - accessToken: []
+ parameters:
+ - in: path
+ type: string
+ name: roomId
+ description: The ID of the room containing the parent event.
+ required: true
+ x-example: "!636q39766251:matrix.org"
+ - in: path
+ type: string
+ name: eventId
+ description: The ID of the parent event whose child events are to be returned.
+ required: true
+ x-example: "$asfDuShaf7Gafaw"
+ - in: path
+ type: string
+ name: relType
+ description: |-
+ The [relationship type](/client-server-api/#relationship-types) to search for.
+ required: true
+ x-example: "org.example.my_relation"
+ - in: query
+ type: string
+ name: from
+ description: |-
+ The pagination token to start returning results from. If not supplied, results
+ start at the most recent topological event known to the server.
+
+ Can be a `next_batch` token from a previous call, or a returned
+ `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages),
+ or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync).
+ required: false
+ x-example: "page2_token"
+ - in: query
+ type: string
+ name: to
+ description: |-
+ The pagination token to stop returning results at. If not supplied, results
+ continue up to `limit` or until there are no more events.
+
+ Like `from`, this can be a previous token from a prior call to this endpoint
+ or from `/messages` or `/sync`.
+ required: false
+ x-example: "page3_token"
+ - in: query
+ type: integer
+ name: limit
+ description: |-
+ The maximum number of results to return in a single `chunk`. The server can
+ and should apply a maximum value to this parameter to avoid large responses.
+
+ Similarly, the server should apply a default value when not supplied.
+ required: false
+ x-example: 20
+ responses:
+ # note: this endpoint deliberately does not support rate limiting, therefore a
+ # 429 error response is not included.
+
+ 200:
+ description: |-
+ The paginated child events which point to the parent. If no events are
+ pointing to the parent or the pagination yields no results, an empty `chunk`
+ is returned.
+ examples:
+ application/json: {
+ "chunk": [{
+ "room_id": "!636q39766251:matrix.org",
+ "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml",
+ "content": {
+ "m.relates_to": {
+ "rel_type": "org.example.my_relation",
+ "event_id": "$asfDuShaf7Gafaw"
+ }
+ }
+ }],
+ "next_batch": "page2_token",
+ "prev_batch": "page1_token"
+ }
+ schema:
+ type: object
+ properties:
+ chunk:
+ title: "ChildEventsChunk"
+ type: array
+ description: |-
+ The child events of the requested event, ordered topologically
+ most-recent first. The events returned will match the `relType`
+ supplied in the URL.
+ items:
+ allOf:
+ - "$ref": "definitions/client_event.yaml"
+ next_batch:
+ type: string
+ description: |-
+ An opaque string representing a pagination token. The absence of this token
+ means there are no more results to fetch and the client should stop paginating.
+ prev_batch:
+ type: string
+ description: |-
+ An opaque string representing a pagination token. The absence of this token
+ means this is the start of the result set, i.e. this is the first batch/page.
+ required: ['chunk']
+ 404:
+ description: |-
+ The parent event was not found or the user does not have permission to read
+ this event (it might be contained in history that is not accessible to the user).
+ examples:
+ application/json: {
+ "errcode": "M_NOT_FOUND",
+ "error": "Event not found."
+ }
+ schema:
+ "$ref": "definitions/errors/error.yaml"
+ tags:
+ - Event relationships
+ # The same as above, with added `/{eventType}`
+ "/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}":
+ get:
+ summary: Get the child events for a given parent event, with a given `relType` and `eventType`.
+ description: |-
+ Retrieve all of the child events for a given parent event which relate to the parent
+ using the given `relType` and have the given `eventType`.
+
+ Note that when paginating the `from` token should be "after" the `to` token in
+ terms of topological ordering, because it is only possible to paginate "backwards"
+ through events, starting at `from`.
+
+ For example, passing a `from` token from page 2 of the results, and a `to` token
+ from page 1, would return the empty set. The caller can use a `from` token from
+ page 1 and a `to` token from page 2 to paginate over the same range, however.
+ operationId: getRelatingEventsWithRelTypeAndEventType
+ security:
+ - accessToken: []
+ parameters:
+ - in: path
+ type: string
+ name: roomId
+ description: The ID of the room containing the parent event.
+ required: true
+ x-example: "!636q39766251:matrix.org"
+ - in: path
+ type: string
+ name: eventId
+ description: The ID of the parent event whose child events are to be returned.
+ required: true
+ x-example: "$asfDuShaf7Gafaw"
+ - in: path
+ type: string
+ name: relType
+ description: |-
+ The [relationship type](/client-server-api/#relationship-types) to search for.
+ required: true
+ x-example: "org.example.my_relation"
+ - in: path
+ type: string
+ name: eventType
+ description: |-
+ The event type of child events to search for.
+
+ Note that in encrypted rooms this will typically always be `m.room.encrypted`
+ regardless of the event type contained within the encrypted payload.
+ required: true
+ x-example: "m.room.message"
+ - in: query
+ type: string
+ name: from
+ description: |-
+ The pagination token to start returning results from. If not supplied, results
+ start at the most recent topological event known to the server.
+
+ Can be a `next_batch` token from a previous call, or a returned
+ `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages),
+ or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync).
+ required: false
+ x-example: "page2_token"
+ - in: query
+ type: string
+ name: to
+ description: |-
+ The pagination token to stop returning results at. If not supplied, results
+ continue up to `limit` or until there are no more events.
+
+ Like `from`, this can be a previous token from a prior call to this endpoint
+ or from `/messages` or `/sync`.
+ required: false
+ x-example: "page3_token"
+ - in: query
+ type: integer
+ name: limit
+ description: |-
+ The maximum number of results to return in a single `chunk`. The server can
+ and should apply a maximum value to this parameter to avoid large responses.
+
+ Similarly, the server should apply a default value when not supplied.
+ required: false
+ x-example: 20
+ responses:
+ # note: this endpoint deliberately does not support rate limiting, therefore a
+ # 429 error response is not included.
+
+ 200:
+ description: |-
+ The paginated child events which point to the parent. If no events are
+ pointing to the parent or the pagination yields no results, an empty `chunk`
+ is returned.
+ examples:
+ application/json: {
+ "chunk": [{
+ "room_id": "!636q39766251:matrix.org",
+ "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml",
+ "content": {
+ "m.relates_to": {
+ "rel_type": "org.example.my_relation",
+ "event_id": "$asfDuShaf7Gafaw"
+ }
+ }
+ }],
+ "next_batch": "page2_token",
+ "prev_batch": "page1_token"
+ }
+ schema:
+ type: object
+ properties:
+ chunk:
+ title: "ChildEventsChunk"
+ type: array
+ description: |-
+ The child events of the requested event, ordered topologically most-recent
+ first. The events returned will match the `relType` and `eventType` supplied
+ in the URL.
+ items:
+ allOf:
+ - "$ref": "definitions/client_event.yaml"
+ next_batch:
+ type: string
+ description: |-
+ An opaque string representing a pagination token. The absence of this token
+ means there are no more results to fetch and the client should stop paginating.
+ prev_batch:
+ type: string
+ description: |-
+ An opaque string representing a pagination token. The absence of this token
+ means this is the start of the result set, i.e. this is the first batch/page.
+ required: ['chunk']
+ 404:
+ description: |-
+ The parent event was not found or the user does not have permission to read
+ this event (it might be contained in history that is not accessible to the user).
+ examples:
+ application/json: {
+ "errcode": "M_NOT_FOUND",
+ "error": "Event not found."
+ }
+ schema:
+ "$ref": "definitions/errors/error.yaml"
+ tags:
+ - Event relationships
+
diff --git a/data/api/client-server/space_hierarchy.yaml b/data/api/client-server/space_hierarchy.yaml
index 607eb8d1..309b99e3 100644
--- a/data/api/client-server/space_hierarchy.yaml
+++ b/data/api/client-server/space_hierarchy.yaml
@@ -58,7 +58,7 @@ paths:
contents.
x-example: true
- in: query
- type: number
+ type: integer
name: limit
description: |-
Optional limit for the maximum number of rooms to include per response. Must be an integer
@@ -67,7 +67,7 @@ paths:
Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.
x-example: 20
- in: query
- type: number
+ type: integer
name: max_depth
description: |-
Optional limit for how far to go into the space. Must be a non-negative integer.
@@ -149,7 +149,7 @@ paths:
format: int64
description: The `origin_server_ts` for the event.
required: [origin_server_ts]
- required: [room_type, children_state]
+ required: [children_state]
next_batch:
type: string
description: |-
diff --git a/data/api/server-server/space_hierarchy.yaml b/data/api/server-server/space_hierarchy.yaml
index cb30fa0f..834848c9 100644
--- a/data/api/server-server/space_hierarchy.yaml
+++ b/data/api/server-server/space_hierarchy.yaml
@@ -158,7 +158,7 @@ paths:
format: int64
description: The `origin_server_ts` for the event.
required: [origin_server_ts]
- required: [room_type, allowed_room_ids, children_state]
+ required: [children_state]
children:
type: array
description: |-
diff --git a/data/event-schemas/schema/m.room.encrypted.yaml b/data/event-schemas/schema/m.room.encrypted.yaml
index 32e86902..51024f7e 100644
--- a/data/event-schemas/schema/m.room.encrypted.yaml
+++ b/data/event-schemas/schema/m.room.encrypted.yaml
@@ -40,10 +40,35 @@ properties:
Olm event. For more details, see [Messaging Algorithms](/client-server-api/#messaging-algorithms).
sender_key:
type: string
- description: The Curve25519 key of the sender.
+ x-changedInMatrixVersion:
+ 1.3: |-
+ Previously this field was required, however given it offers no additional
+ security or privacy benefit it has been deprecated for Megolm messages.
+ See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) for more information.
+ description: |-
+ The Curve25519 key of the sender. Required (not deprecated) if not using Megolm.
+
+ **Deprecated**: This field provides no additional security or privacy benefit
+ for Megolm messages and must not be read from if the encrypted event is using
+ Megolm. It should still be included on outgoing messages, however must not be
+ used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2)
+ for more information.
device_id:
type: string
- description: The ID of the sending device. Required with Megolm.
+ x-changedInMatrixVersion:
+ 1.3: |-
+ Previously this field was required for Megolm messages, however given it
+ offers no additional security or privacy benefit it has been deprecated
+ for Megolm messages. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) for
+ more information.
+ description: |-
+ The ID of the sending device.
+
+ **Deprecated**: This field provides no additional security or privacy benefit
+ for Megolm messages and must not be read from if the encrypted event is using
+ Megolm. It should still be included on outgoing messages, however must not be
+ used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2)
+ for more information.
session_id:
type: string
description: |-
@@ -51,7 +76,6 @@ properties:
Megolm.
required:
- algorithm
- - sender_key
- ciphertext
type: object
type:
diff --git a/data/event-schemas/schema/m.room.join_rules.yaml b/data/event-schemas/schema/m.room.join_rules.yaml
index dbac60d5..d5f8eb2d 100644
--- a/data/event-schemas/schema/m.room.join_rules.yaml
+++ b/data/event-schemas/schema/m.room.join_rules.yaml
@@ -12,6 +12,10 @@ description: |
* `restricted` - anyone able to satisfy at least one of the allow conditions is
able to join the room without prior action. Otherwise, an invite is required.
Only available in rooms [which support the join rule](/rooms/#feature-matrix).
+ * `knock_restricted` - a user can request an invite using the same functions offered
+ by the `knock` join rule, or can attempt to join having satisfied an allow condition
+ per the `restricted` join rule. Only available in rooms
+ [which support the join rule](/rooms/#feature-matrix).
* `private` - reserved without implementation. No significant meaning.
properties:
content:
diff --git a/data/event-schemas/schema/m.room_key_request.yaml b/data/event-schemas/schema/m.room_key_request.yaml
index 99afdb19..acabe2d9 100644
--- a/data/event-schemas/schema/m.room_key_request.yaml
+++ b/data/event-schemas/schema/m.room_key_request.yaml
@@ -23,8 +23,19 @@ properties:
description: The room where the key is used.
sender_key:
type: string
+ x-changedInMatrixVersion:
+ 1.3: |-
+ Previously this field was required, however given it offers no additional
+ security or privacy benefit it has been deprecated. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2)
+ for more information.
description: |-
The Curve25519 key of the device which initiated the session originally.
+
+ **Deprecated**: This field provides no additional security or privacy benefit
+ and must not be read from. It should still be included on outgoing messages
+ (if the event for which keys are being requested for *also* has a `sender_key`),
+ however must not be used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2)
+ for more information.
session_id:
type: string
description: The ID of the session that the key is for.
@@ -32,7 +43,6 @@ properties:
- algorithm
- room_id
- session_id
- - sender_key
type: object
title: RequestedKeyInfo
action: