客户端-服务器 API

本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。

客户端-服务器 API 允许客户端发送消息、控制房间以及同步会话历史。该 API 既支持不存储状态、按需从服务器延迟加载数据的轻量级客户端,也支持维护完整本地持久状态副本的重量级客户端。

API 标准

Matrix 中客户端与服务器通信的强制性基线是通过 HTTP API 交换 JSON 对象。未来可以指定更高效的传输方式,作为可选扩展。

建议使用 HTTPS 进行通信。除测试环境外,不推荐使用明文 HTTP。

客户端通过不透明的 access_token 字符串进行认证(详见 客户端认证)。

除下述例外,所有 POSTPUT 端点均要求客户端在请求体中提供(可能为空的)JSON 对象。对于所有带有 JSON 请求体的请求,客户端应在请求头中带上 Content-Type: application/json,但这不是强制要求。

例外包括:

同理,所有端点都要求服务器返回一个 JSON 对象,除非对 内容仓库模块 中媒体下载端点返回的 200 响应。服务器必须为所有 JSON 响应添加 Content-Type: application/json 响应头。

所有请求和响应中的 JSON 数据必须使用 UTF-8 编码。

参见附录中的 Matrix API 规范约定 以及下文 Web 浏览器客户端 对服务器响应的附加要求。

标准错误响应

Matrix API 层发生的任何错误必须返回“标准错误响应”。格式如下:

{
  "errcode": "<error code>",
  "error": "<error message>"
}

error 字符串为易读的错误消息,通常是一句简要说明出错原因的语句。

errcode 是唯一字符串,可用于处理错误信息,例如 M_FORBIDDEN。错误码的命名空间应全部大写,后接一个下划线 _。例如自定义命名空间 com.mydomain.here 和代码 FORBIDDEN,错误码应为 COM.MYDOMAIN.HERE_FORBIDDEN。本规范定义的错误码以 M_ 开头。

某些 errcode 定义了附加的键应在错误响应对象中出现,但 errorerrcode必须始终存在。

一般建议通过错误码而不是 HTTP 状态码来表达错误。当遇到 M_UNKNOWN 错误码时,客户端应优先参考 HTTP 状态码,作为更可靠的问题指示。例如,若客户端收到 M_NOT_FOUND 错误码但请求返回 400 Bad Request,则应按资源未找到处理该错误。然而,若客户端收到 M_UNKNOWN 错误码和 400 Bad Request,应认为请求无效。

常见错误码

这些错误码可以被任意 API 端点返回:

M_FORBIDDEN 禁止访问,例如无权限加入房间、登录失败。

M_UNKNOWN_TOKEN 指定的访问令牌或刷新令牌未被识别。

若 HTTP 401 响应返回时包含额外参数 soft_logout,详见 软登出说明

M_MISSING_TOKEN 请求未指定访问令牌。

M_USER_LOCKED 账户已被锁定,暂时无法使用。

M_USER_SUSPENDED 账户已被停用,目前仅可执行有限操作。

M_BAD_JSON 请求包含合法的 JSON,但某种方式上格式不正确,例如缺少必需键、键值无效等。

M_NOT_JSON 请求未包含有效的 JSON。

M_NOT_FOUND 请求未找到资源。

M_LIMIT_EXCEEDED 短时间内请求过多。请等待一段时间后重试。参见 速率限制

M_UNRECOGNIZED 服务器无法理解请求。若端点未实现,建议返回 404;端点已实现但使用了错误 HTTP 方法,应返回 405。

M_UNKNOWN 发生未知错误。

其他错误码

下列错误码专用于特定端点。

M_UNAUTHORIZED 请求未正确验证,通常由于登录失败。

M_USER_DEACTIVATED 请求关联的用户 ID 已停用。通常见于验证身份的端点,诸如 /login

M_USER_IN_USE 尝试注册已被占用的用户 ID 时遇到。

M_INVALID_USERNAME 尝试注册非法用户 ID 时遇到。

M_ROOM_IN_USE createRoom API 提供的房间别名已被占用时返回。

M_INVALID_ROOM_STATE createRoom API 提供的初始状态无效时返回。

M_THREEPID_IN_USE API 提供的 threepid 已被另一账号使用,无法再次使用。

M_THREEPID_NOT_FOUND API 提供的 threepid 未找到记录,无法使用。

M_THREEPID_AUTH_FAILED 无法对第三方标识符执行认证。

M_THREEPID_DENIED 服务器不允许使用该第三方标识符。例如服务器只允许特定域名的邮箱。

M_SERVER_NOT_TRUSTED 客户端请求用到的第三方服务器(如身份服务器)不被当前服务器信任。

M_UNSUPPORTED_ROOM_VERSION 客户端请求创建房间时使用了服务器不支持的房间版本。

M_INCOMPATIBLE_ROOM_VERSION 客户端尝试加入服务器不支持版本的房间。请检查错误响应中的 room_version 属性以获取房间版本。

M_BAD_STATE 无法执行请求的状态变更,例如尝试解禁未被禁言的用户。

M_GUEST_ACCESS_FORBIDDEN 房间或资源不允许访客访问。

M_CAPTCHA_NEEDED 完成请求需要验证码。

M_CAPTCHA_INVALID 提供的验证码与预期不符。

M_MISSING_PARAM 请求缺少必需参数。

M_INVALID_PARAM 请求参数值类型错误。例如,服务器期望整数却收到字符串。

M_TOO_LARGE 请求或实体体积过大。

M_EXCLUSIVE 请求的资源被应用服务保留,或发起请求的应用服务未创建该资源。

M_RESOURCE_LIMIT_EXCEEDED 由于主服务器资源限制,无法完成请求。例如,在共享主机环境的主服务器使用了过多内存或磁盘空间。错误必须包含 admin_contact 字段为用户提供联系方式。通常该错误会出现在尝试修改状态的路由(如发送消息、账户数据)而不是只读路由上(如 /sync/user/{userId}/account_data/{type} 等)。

M_CANNOT_LEAVE_SERVER_NOTICE_ROOM 用户无法拒绝加入服务器通知房间的邀请。详见 服务器通知 模块。

M_THREEPID_MEDIUM_NOT_SUPPORTED 主服务器不支持添加指定 medium 的第三方标识符。

M_THREEPID_IN_USE 客户端指定的第三方标识符不可接受,因为已被使用。

速率限制

主服务器应当实现速率限制以降低被过载风险。当请求因速率限制被拒绝时,应返回标准错误响应格式如下:

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "string",
  "retry_after_ms": integer (可选,已弃用)
}

主服务器为所有 429 状态码的响应包含 Retry-After 响应头。

retry_after_ms 属性可告知客户端需等待多少毫秒后再试。该属性已弃用,应优先采用 Retry-After 响应头。

[Changed in v1.10]retry_after_ms 属性已弃用,请使用 Retry-After 响应头。

事务标识符

客户端-服务器 API 通常使用 HTTP PUT,在 HTTP 路径中带上传递由客户端生成的事务标识符(Transaction ID)。

事务 ID 的目的在于帮助主服务器区分新请求与前次请求的重发,实现请求幂等性。

事务 ID 用于此目的。

请求完成后,客户端应更换下一次请求的 {txnId}。具体生成方式由实现自定,推荐使用 version 4 UUID 或当前时间戳与单调递增整数的拼接。

主服务器应当认定若事务 ID 与以前请求一致且 HTTP 请求路径一致,则为重发。

识别为重发时,主服务器应返回与原始请求相同的 HTTP 响应码和内容。例如 PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId} 会以 200 OK 和原始请求响应体中的 event_id 返回。

事务 ID 的作用范围仅限于单一设备和单一 HTTP 端点。换言之,同一设备可以用相同的事务 ID 向 PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}PUT /_matrix/client/v3/sendToDevice/{eventType}/{txnId} 请求,两者被视为互不相关端点。同样地,客户端在两次登录之间,用相同的事务 ID 进行两次请求也算不同请求(除非登录时指定了已存在的 device_id)。但如果在刷新访问令牌后,对同一端点重复使用事务 ID,则视为重复请求并予以忽略。参见 访问令牌与设备的关系

部分 API 端点允许或要求使用无需事务 ID 的 POST 请求。可选情况下,强烈建议使用 PUT

v1.7 之前,事务 ID 的作用范围为“客户端会话”,而非设备。

Web 浏览器客户端

实际情况会有部分客户端以 web 浏览器或类似环境运行。此时主服务器应当响应预检请求,并在所有请求上提供跨域资源共享(CORS)头部。

服务器必须预期客户端将向其发送 OPTIONS 请求,以便客户端获取 CORS 头。本规范中的所有端点均支持 OPTIONS 方法,但服务器收到 OPTIONS 请求时不得执行端点定义的任何业务逻辑。

当客户端访问服务器发起请求,服务器应返回该路由的 CORS 头。推荐所有请求返回的 CORS 头为:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization

[Added in v1.13] Access-Control-Allow-Methods 响应头的推荐值仅覆盖规范现有端点。服务器如支持额外端点或方法,应相应添加。

此章节将在端点新增方法时同步更新。未来可能支持的如 PATCHHEAD

服务器发现

为便于用户无需明确指定主服务器 URL 或其它参数即可连接到 Matrix 服务器,客户端在登录时通过自动发现机制根据用户的 Matrix ID 确定服务器 URL。

本节下列术语含义如下:

PROMPT 以适合当前客户端用户体验的方式从用户获取特定信息(客户端如有合适交互能力),如无法良好交互则可选择放弃。

IGNORE 停止当前自动发现机制。如无可用自动发现机制,则客户端可用其它方式获取所需参数(如提示用户或使用默认值)。

FAIL_PROMPT 提示用户自动发现因数据无效/为空而失败,并要求提供相应参数。

FAIL_ERROR 通知用户自动发现未返回可用 URL,当前登录流程终止,此时已获取合法数据但无服务器可用,不应再尝试其他可能性,用户需自主决定下一步。

Well-known URI

托管 .well-known JSON 文件的服务器提供 CORS 头,参见 CORS

.well-known 方法指在预定位置提供 JSON 文件以指定参数值。流程如下:

  1. 服务器名 规则,从用户 Matrix ID 截取第一个冒号后片段。
  2. 语法 从服务器名提取主机名。
  3. 以 GET 请求 https://hostname/.well-known/matrix/client
    1. 返回状态码 404 时处理为 IGNORE
    2. 状态码非 200 或响应体为空,处理为 FAIL_PROMPT
    3. 解析响应体为 JSON 对象,如失败则 FAIL_PROMPT
    4. m.homeserver 属性提取 base_url,该值作为主服务器基础 URL。未提供则 FAIL_PROMPT
    5. 验证主服务器基础 URL:
      1. 按 URL 解析,如错误则 FAIL_ERROR
      2. 客户端连接 /_matrix/client/versions 端点,确保无错误并验证响应符合预期格式。如任一步失败,处理为 FAIL_ERROR。这步仅用于排除配置错误,确认地址有效。
      3. 注意 base_url 可能带 / 结尾,调用方需兼容两种。
    6. 若存在 m.identity_server,从中提取 base_url 用作身份服务器基础 URL。其验证与上面主服务器 URL 验证一致,连接端点为 /_matrix/identity/v2。如果 m.identity_server 存在但无 base_url,则 FAIL_PROMPT

GET /.well-known/matrix/client


Gets discovery information about the domain. The file may include additional keys, which MUST follow the Java package naming convention, e.g. com.example.myapp.property. This ensures property names are suitably namespaced for each application and reduces the risk of clashes.

Note that this endpoint is not necessarily handled by the homeserver, but by another webserver, to be used for discovering the homeserver URL.

Rate-limited: No
Requires authentication: No

Request

No request parameters or request body.


Responses

Status Description
200 Server discovery information.
404 No server discovery information available.

200 response

Discovery Information
Name Type Description
m.homeserver Homeserver Information

Required: Used by clients to discover homeserver information.

m.identity_server Identity Server Information

Used by clients to discover identity server information.

<Other properties>

Application-dependent keys using Java package naming convention.

Homeserver Information
Name Type Description
base_url URI

Required: The base URL for the homeserver for client-server connections.

Identity Server Information
Name Type Description
base_url URI

Required: The base URL for the identity server for client-server connections.

{
  "m.homeserver": {
    "base_url": "https://matrix.example.com"
  },
  "m.identity_server": {
    "base_url": "https://identity.example.com"
  },
  "org.example.custom.property": {
    "app_url": "https://custom.app.example.org"
  }
}

GET /_matrix/client/versions


Changed in v1.10: This endpoint can behave differently when authentication is provided.

Gets the versions of the specification supported by the server.

Values will take the form vX.Y or rX.Y.Z in historical cases. See the Specification Versioning for more information.

The server may additionally advertise experimental features it supports through unstable_features. These features should be namespaced and may optionally include version information within their name if desired. Features listed here are not for optionally toggling parts of the Matrix specification and should only be used to advertise support for a feature which has not yet landed in the spec. For example, a feature currently undergoing the proposal process may appear here and eventually be taken off this list once the feature lands in the spec and the server deems it reasonable to do so. Servers can choose to enable some features only for some users, so clients should include authentication in the request to get all the features available for the logged-in user. If no authentication is provided, the server should only return the features available to all users. Servers may wish to keep advertising features here after they’ve been released into the spec to give clients a chance to upgrade appropriately. Additionally, clients should avoid using unstable features in their stable releases.

Rate-limited: No
Requires authentication: Optional

Request

No request parameters or request body.


Responses

Status Description
200 The versions supported by the server.

200 response

Name Type Description
unstable_features {string: boolean}

Experimental features the server supports. Features not listed here, or the lack of this property all together, indicate that a feature is not supported.

versions [string]

Required: The supported versions.

{
  "unstable_features": {
    "org.example.my_feature": true
  },
  "versions": [
    "r0.0.1",
    "v1.1"
  ]
}

GET /.well-known/matrix/support


Added in v1.10

Gets server admin contact and support page of the domain.

Like the well-known discovery URI, this should be accessed with the hostname of the homeserver by making a GET request to https://hostname/.well-known/matrix/support.

Note that this endpoint is not necessarily handled by the homeserver. It may be served by another webserver, used for discovering support information for the homeserver.

Rate-limited: No
Requires authentication: No

Request

No request parameters or request body.


Responses

Status Description
200 Server support information.
404 No server support information available.

200 response

Name Type Description
contacts [Contact]

Ways to contact the server administrator.

At least one of contacts or support_page is required. If only contacts is set, it must contain at least one item.

support_page URI

The URL of a page to give users help specific to the homeserver, like extra login/registration steps.

At least one of contacts or support_page is required.

Contact
Name Type Description
email_address Email Address

An email address to reach the administrator.

At least one of matrix_id or email_address is required.

matrix_id User ID

A Matrix User ID representing the administrator.

It could be an account registered on a different homeserver so the administrator can be contacted when the homeserver is down.

At least one of matrix_id or email_address is required.

role string

Required: An informal description of what the contact methods are used for.

m.role.admin is a catch-all role for any queries and m.role.security is intended for sensitive requests.

Unspecified roles are permitted through the use of Namespaced Identifiers.

One of: [m.role.admin, m.role.security].

{
  "contacts": [
    {
      "email_address": "admin@example.org",
      "matrix_id": "@admin:example.org",
      "role": "m.role.admin"
    },
    {
      "email_address": "security@example.org",
      "role": "m.role.security"
    }
  ],
  "support_page": "https://example.org/support.html"
}

客户端认证

多数 API 端点要求用户通过访问令牌(access token)认证身份。访问令牌通常通过 登录注册 流程获得,令牌可能失效;可用刷新令牌重新生成。

本规范不强制规定访问令牌格式。客户端应将其视为不透明字节序列。服务器可自由选择合适的格式。服务器实现者可参考macaroons

使用访问令牌

可通过请求头及 Authentication Bearer 方案提供访问令牌:Authorization: Bearer TheTokenHere

也可通过查询字符串参数 access_token=TheTokenHere 提供,但因易被日志泄露,已弃用,客户端不应使用。

主服务器必须同时支持两种方式。

[Changed in v1.11] 以查询字符串方式传递访问令牌现已弃用。

如缺少或非法凭据,请求返回 401 状态及错误码,分别为 M_MISSING_TOKENM_UNKNOWN_TOKEN。注意,M_UNKNOWN_TOKEN 可能有以下四种情况:

  1. 访问令牌从未有效;
  2. 访问令牌已注销;
  3. 访问令牌已软登出
  4. [Added in v1.3] 访问令牌需要刷新

当客户端收到 M_UNKNOWN_TOKEN 错误码,应:

  • 如有刷新令牌,尝试刷新令牌
  • 若响应中 soft_logouttrue,可提示用户重新登录并保留客户端已持久化的信息;
  • 否则,视为用户已登出。

访问令牌与设备关系

客户端设备与访问令牌及刷新令牌密切相关。Matrix 服务器应记录每个访问令牌与刷新令牌所绑定设备,以保证请求正确处理。用刷新令牌生成新访问/刷新令牌时,新一对令牌归属于原刷新令牌关联设备。

默认情况下,登录注册流程会自动生成新 device_id。客户端也可自定义 device_id 或(用户不变时)复用设备,并在请求体中带上 device_id;若客户端传入 device_id,服务器会使该设备此前的访问及刷新令牌失效。

刷新访问令牌

[Added in v1.3]

访问令牌可能在一定时限后过期。使用过期令牌发起 HTTP 调用会返回 M_UNKNOWN_TOKEN 错误码,且建议带有 soft_logout: true。客户端收到此错误且持有刷新令牌应调用 /refresh 刷新令牌。即使尚未过期也可主动刷新。刷新成功后应使用新令牌发起后续请求,并可用新令牌重试先前失败请求。返回新刷新令牌时,旧刷新令牌即失效,后续刷新需用新令牌。

旧刷新令牌在新访问/刷新令牌使用前仍有效,之后即被吊销,确保客户端若未取到或保存新令牌还能重复刷新。

若令牌刷新失败且错误响应带有 soft_logout: true,可视为软登出,尝试重新登录获取新访问令牌。否则,客户端应视为用户已登出。

不支持刷新令牌的客户端行为由主服务器决定;客户端通过在 /login/register 请求体声明 refresh_token: true 表明支持刷新令牌。例如主服务器可允许使用永不过期的访问令牌,或依赖客户端软登出行为。

软登出

若服务器要求重新认证但不希望立即失效当前客户端会话,可通过在 M_UNKNOWN_TOKEN 错误响应中包含 soft_logout: true 标志进行软登出;soft_logout 默认为 false。若 soft_logout 被省略或为 false,则服务器已销毁会话,客户端不得重复利用;任何客户端持久信息如加密密钥和设备信息等须丢弃。若 soft_logouttrue,客户端可复用持久状态。

[Changed in v1.3] 客户端收到软登出可优先刷新访问令牌(如有刷新令牌)。如无刷新令牌或刷新失败且为软登出,可借登录 API 指定已有设备 ID 获取新访问令牌。

[Changed in v1.12] 若响应同时携带 M_USER_LOCKED 错误码,则直到账户解锁前无法获取新的访问令牌。

用户交互式认证 API

总览

部分 API 端点需互动式认证(User-Interactive Authentication)。主服务器可提供多种认证方式,如用户名密码、单点登录(SSO)等。本规范不限制主服务器背后授权方式,仅定义标准接口以使任意客户端可登录任何主服务器。

认证过程由一系列“阶段”组成,每个阶段客户端向服务器提交一组认证数据并等待响应,响应可能为最终成功或要求下一阶段,交互继续至最终成功。

服务器为端点提供一种或多种“流”供客户端完成认证,每种流由一组有序阶段组成。客户端可自由选择认证流,但阶段必须依次完成。未按规定流程完成应返回 401。如所有阶段完成,认证即告完成,API 调用正常返回。

REST API 中的用户交互式认证

如本文档所述 REST API,认证流程由客户端与服务器之间交换 JSON 字典实现。服务器通过 401 响应体说明所需认证数据,客户端将其置于请求参数 auth 中提交。

客户端首次请求勿带 auth 参数。主服务器返回 401 状态码及如下 JSON 体:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "flows": [
    {
      "stages": [ "example.type.foo", "example.type.bar" ]
    },
    {
      "stages": [ "example.type.foo", "example.type.baz" ]
    }
  ],
  "params": {
      "example.type.baz": {
          "example_key": "foobar"
      }
  },
  "session": "xxxxxx"
}

flows 外,该对象包含:

  • params: 提供客户端使用所列认证类型所需补充信息。例如某认证类型作为键存储于此字典。举例 OAuth 客户端 ID 可放此信息。
  • session: 服务器颁发的会话标识符,客户后续认证时需返回。

客户端选定流并尝试完成首个阶段。向服务器重复发送原请求,新增 auth 字段,内容为类型名(type),会话标识符(session),以及类型相关的其它认证信息。例如阶段类型为 example.type.foo 时:

POST /_matrix/client/v3/endpoint HTTP/1.1
Content-Type: application/json
{
  "a_request_parameter": "something",
  "another_request_parameter": "something else",
  "auth": {
      "type": "example.type.foo",
      "session": "xxxxxx",
      "example_credential": "verypoorsharedsecret"
  }
}

如服务器认证成功但仍需更多阶段,则返回 401、响应结构与首次 401 相同,另加 completed 列表指示已完成的认证类型:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "completed": [ "example.type.foo" ],
  "flows": [
    {
      "stages": [ "example.type.foo", "example.type.bar" ]
    },
    {
      "stages": [ "example.type.foo", "example.type.baz" ]
    }
  ],
  "params": {
      "example.type.baz": {
          "example_key": "foobar"
      }
  },
  "session": "xxxxxx"
}

如某阶段需多次请求才能完成,则响应同未认证,仅追加认证类型自定义内容。

若服务器认为当前阶段尝试失败,并允许重试,则返回同上,只是多了标准错误字段 errcodeerror。例如:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "errcode": "M_FORBIDDEN",
  "error": "Invalid password",
  "completed": [ "example.type.foo" ],
  "flows": [
    {
      "stages": [ "example.type.foo", "example.type.bar" ]
    },
    {
      "stages": [ "example.type.foo", "example.type.baz" ]
    }
  ],
  "params": {
      "example.type.baz": {
          "example_key": "foobar"
      }
  },
  "session": "xxxxxx"
}

如请求失败原因为认证以外的其他原因,则依标准格式返回错误消息。例如:

HTTP/1.1 400 Bad request
Content-Type: application/json
{
  "errcode": "M_EXAMPLE_ERROR",
  "error": "Something was wrong"
}

如已完成某流程全部阶段,主服务器执行业务正常返回。已完成的阶段无法重试,服务器必须返回 401 响应及已完成阶段,或如阶段都已完成则返回业务结果。

某些认证类型可由 Matrix 客户端以外方式完成,例如邮箱确认可通过点击邮件链接。此时,客户端带 session 会话重试,服务器响应与正常认证一致,依类型是否在‘completed’数组确定阶段是否完成。

使用交互式认证的端点,任何无认证数据的请求均不会成功。服务器如允许无认证完成请求应提供仅含 m.login.dummy 的阶段,但必须对无认证请求返回 401。

示例

一个包含三阶段认证流的 API 调用流程如下:

    _______________________
    |       Stage 0         |
    | No auth               |
    |  ___________________  |
    | |_Request_1_________| | <-- 返回“session”键以供后续认证。
    |_______________________|
             |
             |
    _________V_____________
    |       Stage 1         |
    | type: "<auth type1>"  |
    |  ___________________  |
    | |_Request_1_________| |
    |_______________________|
             |
             |
    _________V_____________
    |       Stage 2         |
    | type: "<auth type2>"  |
    |  ___________________  |
    | |_Request_1_________| |
    |  ___________________  |
    | |_Request_2_________| |
    |  ___________________  |
    | |_Request_3_________| |
    |_______________________|
             |
             |
    _________V_____________
    |       Stage 3         |
    | type: "<auth type3>"  |
    |  ___________________  |
    | |_Request_1_________| | <-- 正常返回 API 结果
    |_______________________|

认证类型

本规范定义以下认证类型:

  • m.login.password
  • m.login.recaptcha
  • m.login.sso
  • m.login.email.identity
  • m.login.msisdn
  • m.login.dummy
  • m.login.registration_token
基于密码
类型 描述
m.login.password 客户端提交标识符和明文密码。

用此方式时,auth 内容如下:

{
  "type": "m.login.password",
  "identifier": {
    ...
  },
  "password": "<password>",
  "session": "<session ID>"
}

identifier 属性为用户标识对象,详见 标识符类型

如用 Matrix ID 登录:

{
  "type": "m.login.password",
  "identifier": {
    "type": "m.id.user",
    "user": "<user_id 或用户本地名>"
  },
  "password": "<password>",
  "session": "<session ID>"
}

也可用 /account/3pid 绑定的 3PID 替代 user

{
  "type": "m.login.password",
  "identifier": {
    "type": "m.id.thirdparty",
    "medium": "<第三方标识符 medium>",
    "address": "<用户 third-party 地址>"
  },
  "password": "<password>",
  "session": "<session ID>"
}

如主服务器不识别所提供的 3PID,应响应 403 Forbidden。

Google ReCaptcha
类型 描述
m.login.recaptcha 用户完成 Google ReCaptcha 2.0 验证。

用法如下:

{
  "type": "m.login.recaptcha",
  "response": "<captcha response>",
  "session": "<session ID>"
}
单点登录(SSO)
类型 描述
m.login.sso 通过外部单点登录提供商认证。

客户端用 SSO 完成认证时应采用 Fallback 机制,详见交互式认证中的 SSO

基于邮箱(身份/主服务器)
类型 描述
m.login.email.identity 通过身份服务器(或支持的主服务器)认证邮箱。

用前需在身份服务器(或主服务器)完成邮箱认证。认证后需将 session 信息提交给主服务器。

示例:

{
  "type": "m.login.email.identity",
  "threepid_creds": {
    "sid": "<身份服务器 session id>",
    "client_secret": "<身份服务器客户端密钥>",
    "id_server": "<认证身份服务器地址,例如 'matrix.org:8090'>",
    "id_access_token": "<以前注册身份服务器的 access token>"
  },
  "session": "<session ID>"
}

/requestToken 时未包含 id_server 等,可省略该字段。

基于手机号/MSISDN(身份/主服务器)
类型 描述
m.login.msisdn 通过身份服务器(或主服务器)认证手机号。

用前需在身份服务器(或主服务器)完成手机号认证,后续将 session 信息提交主服务器。

示例:

{
  "type": "m.login.msisdn",
  "threepid_creds": {
    "sid": "<身份服务器 session id>",
    "client_secret": "<身份服务器客户端密钥>",
    "id_server": "<认证身份服务器地址,例如 'matrix.org:8090'>",
    "id_access_token": "<以前注册身份服务器的 access token>"
  },
  "session": "<session ID>"
}

/requestTokenid_server,可省略该字段。

Dummy 认证
类型 描述
m.login.dummy Dummy 认证始终成功且无需额外参数。

Dummy 认证允许服务器无需任何用户交互即可完成请求,也可区分流程(例如存在子集包含关系的两个认证流,可用 Dummy 区分)。用时仅需传 type、session:

{
  "type": "m.login.dummy",
  "session": "<session ID>"
}
令牌注册

[Added in v1.2]

类型 描述
m.login.registration_token 用预共享令牌认证注册账号。

m.login.registration_token 仅适用于 /register 端点。

此类型允许主服务器仅向有限用户开放注册(非完全开放/关闭),需带最大长度 64 的不透明标识符(参见 Opaque Identifier)。服务器可任意定义令牌数量与有效期,如:限定 100 次、2 小时等,过期作废。

用法如下:

{
  "type": "m.login.registration_token",
  "token": "fBVFdqVE",
  "session": "<session ID>"
}

如需确认令牌有效性可用下面的 /validity API,但此 API 不保障使用时令牌一定有效。

GET /_matrix/client/v1/register/m.login.registration_token/validity


Added in v1.2

Queries the server to determine if a given registration token is still valid at the time of request. This is a point-in-time check where the token might still expire by the time it is used.

Servers should be sure to rate limit this endpoint to avoid brute force attacks.

Rate-limited: Yes
Requires authentication: No

Request

Request parameters

query parameters
Name Type Description
token string

Required: The token to check validity of.


Responses

Status Description
200 The check has a result.
403 The homeserver does not permit registration and thus all tokens are considered invalid.
429 This request was rate-limited.

200 response

Name Type Description
valid boolean

Required: True if the token is still valid, false otherwise. This should additionally be false if the token is not a recognised token by the server.

{
  "valid": true
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Registration is not enabled on this homeserver."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
注册时服务条款

[Added in v1.11]

类型 描述
m.login.terms 用户需接受服务条款、隐私政策等政策性文档。

m.login.terms 仅适用于 /register 端点。

主服务器要求新用户接受服务条款等政策性文件。文档可能有多类型、多版本、多语言。

服务器需通过 /register 返回 401,并在 flows 中包含 m.login.termsparams 内有结构见下文

客户端遇到无效参数应终止注册并提示用户错误。

客户端应为每个政策提供勾选框及跳转链接,用户接受后提交仅含 type、session 的 auth 字段:

{
  "type": "m.login.terms",
  "session": "<session ID>"
}

服务器应记录注册过程展现的文档版本。

示例

  1. 客户端注册请求为:

    POST /_matrix/client/v3/register
    
    {
      "username": "cheeky_monkey",
      "password": "ilovebananas"
    }
    
  2. 服务器要求接受条款,返回:

    HTTP/1.1 401 Unauthorized
    Content-Type: application/json
    
    {
      "flows": [
        { "stages": [ "m.login.terms" ] }
      ],
      "params": {
        "m.login.terms": {
          "policies": {
            "terms_of_service": {
              "version": "1.2",
              "en": {
                  "name": "Terms of Service",
                  "url": "https://example.org/somewhere/terms-1.2-en.html"
              },
              "fr": {
                  "name": "Conditions d'utilisation",
                  "url": "https://example.org/somewhere/terms-1.2-fr.html"
              }
            }
          }
        }
      },
      "session": "kasgjaelkgj"
    }
    
  3. 客户端将文档列表展现给用户并提示接受。

  4. 用户确认全部接受后,客户端重复注册请求:

    POST /_matrix/client/v3/register
    
    {
      "username": "cheeky_monkey",
      "password": "ilovebananas",
      "auth": {
        "type": "m.login.terms",
        "session": "kasgjaelkgj"
      }
    }
    
  5. 所有认证步骤均已完成,请求成功:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "access_token": "abc123",
      "device_id": "GHTYAJCE",
      "user_id": "@cheeky_monkey:matrix.org"
    }
    

m.login.terms params


Schema for m.login.terms entry in the params object in a User-Interactive Authentication response.

m.login.terms params
Name Type Description
policies {string: Policy Definition}

Required: A map from “Policy ID” to the current definition of this policy document. The Policy ID is a unique identifier for a given policy document, using the Opaque Identifier Grammar.

Policy Definition
Name Type Description
version string

Required: The version of this policy document. This is provided as a convenience for the client, and uses the Opaque Identifier Grammar.

<Other properties> Policy Translation

Map from language codes to details of the document in that language. Language codes SHOULD be formatted as per Section 2.2 of RFC 5646, though some implementations may use an underscore instead of dash (for example, en_US instead of en-US).

Policy Translation
Name Type Description
name string

Required: The name of this document, in the appropriate language. An arbitrary string with no specified maximum length.

url URI

Required: A link to the text of this document, in the appropriate language. MUST be a valid URI with scheme https:// or http://. Insecure HTTP is discouraged.

Examples

{
  "policies": {
    "privacy_policy": {
      "en": {
        "name": "Privacy Policy",
        "url": "https://example.org/somewhere/privacy-1.2-en.html"
      },
      "fr": {
        "name": "Politique de confidentialité",
        "url": "https://example.org/somewhere/privacy-1.2-fr.html"
      },
      "version": "1.2"
    },
    "terms_of_service": {
      "en": {
        "name": "Terms of Service",
        "url": "https://example.org/somewhere/terms-1.2-en.html"
      },
      "fr": {
        "name": "Conditions d'utilisation",
        "url": "https://example.org/somewhere/terms-1.2-fr.html"
      },
      "version": "1.2"
    }
  }
}

Fallback

客户端无法预期支持所有认证类型。如遇不识别的认证类型可引导用户于浏览器打开备用页面,完成此阶段。URL 格式:

/_matrix/client/v3/auth/<auth type>/fallback/web?session=<session ID>

其中 auth type 为类型名,session ID 为会话标识。

回调页面必须返回 HTML,可以完成该认证并用如下 JS 通知客户端:

if (window.onAuthDone) {
    window.onAuthDone();
} else if (window.opener && window.opener.postMessage) {
    window.opener.postMessage("authDone", "*");
}

这样客户端可在内嵌浏览器用 onAuthDone 回调,或用 HTML5 跨文档消息 API。

收到通知后客户端应以仅含 session ID 的 auth 字段重发请求:

{
  "session": "<session ID>"
}
示例

网页客户端可用如下 JS 打开处理未知认证类型的弹窗:

/**
 * 参数:
 *     homeserverUrl: 主服务器基础地址 (如 "https://matrix.org")
 *     apiEndpoint: 正在使用的 API 端点 (如 "/_matrix/client/v3/account/password")
 *     loginType: 正在认证的类型 (如 "m.login.recaptcha")
 *     sessionID: 主服务器颁发的会话标识符
 *     onComplete: 认证完成的回调,参数为请求响应内容
 */
function unknownLoginType(homeserverUrl, apiEndpoint, loginType, sessionID, onComplete) {
    var popupWindow;

    var eventListener = function(ev) {
        // 检查消息和来源
        if (ev.data !== "authDone" || ev.origin !== homeserverUrl) {
            return;
        }

        // 关闭弹窗
        popupWindow.close();
        window.removeEventListener("message", eventListener);

        // 重发请求
        var requestBody = {
            auth: {
                session: sessionID,
            },
        };

        request({
            method:'POST', url:apiEndpoint, json:requestBody,
        }, onComplete);
    };

    window.addEventListener("message", eventListener);

    var url = homeserverUrl +
        "/_matrix/client/v3/auth/" +
        encodeURIComponent(loginType) +
        "/fallback/web?session=" +
        encodeURIComponent(sessionID);

   popupWindow = window.open(url);
}

标识符类型

部分认证方式通过用户标识符对象(identifier)标识用户。用户标识对象含 type 字段指明类型,根据类型含有不同的必需字段。

本规范定义如下标识符类型:

  • m.id.user
  • m.id.thirdparty
  • m.id.phone
Matrix 用户 ID
类型 描述
m.id.user 以 Matrix ID 标识用户。

通过 Matrix ID 标识用户,既可以是全限定 ID,也可以是本地用户名。

"identifier": {
  "type": "m.id.user",
  "user": "<user_id 或本地用户名>"
}
第三方 ID
类型 描述
m.id.thirdparty 以规范化第三方标识符标识用户。

通过 3PID 标识用户,3PID 绑定见 /account/3pid,medium 列表见 3PID 类型

"identifier": {
  "type": "m.id.thirdparty",
  "medium": "<第三方标识符类型>",
  "address": "<用户第三方标识符地址>"
}
手机号
类型 描述
m.id.phone 以手机号标识用户。

以绑定手机号标识用户,手机号可由用户原样输入,由主服务器规范化。如需客户端自规范,可用 m.id.thirdparty 类型并设置 medium: msisdn

"identifier": {
  "type": "m.id.phone",
  "country": "<手机号归属国家>",
  "phone": "<手机号>"
}

country 是两位大写 ISO-3166-1 alpha-2 国家码,phone 按该区域拨号规范解析。

登录

客户端可用 /login API 获取访问令牌。

该端点 当前不 使用 用户交互式认证 API

用户名/密码登录示例:

{
  "type": "m.login.password",
  "identifier": {
    "type": "m.id.user",
    "user": "<user_id 或本地用户名>"
  },
  "password": "<password>"
}

也可用 /account/3pid 绑定的 3PID:

{
  "type": "m.login.password",
  "identifier": {
    "medium": "<第三方标识符类型>",
    "address": "<用户规范化的第三方标识符地址>"
  },
  "password": "<password>"
}

主服务器不识别 3PID 时返回 403 Forbidden。

用登录令牌登录的方法如下:

{
  "type": "m.login.token",
  "token": "<login token>"
}

token 必须编码用户 ID(因请求中无其它身份信息)。如令牌无效,则返回 403 Forbidden 和错误码 M_FORBIDDEN

若主服务器声明支持 m.login.sso 流,且客户端支持,客户端应重定向用户至 通过 SSO 客户端登录/redirect 端点。认证完成后,需要匹配 m.login.token 类型发送 /login 请求。

[Added in v1.7] 已认证客户端如主服务器支持可通过 POST /login/get_token 为自己账户生成一次性登录令牌。

GET /_matrix/client/v3/login


Gets the homeserver’s supported login types to authenticate users. Clients should pick one of these and supply it as the type when logging in.

Rate-limited: Yes
Requires authentication: No

Request

No request parameters or request body.


Responses

Status Description
200 The login types the homeserver supports
429 This request was rate-limited.

200 response

Name Type Description
flows [LoginFlow]

The homeserver’s supported login types

LoginFlow
Name Type Description
get_login_token boolean

If type is m.login.token, an optional field to indicate to the unauthenticated client that the homeserver supports the POST /login/get_token endpoint. Note that supporting the endpoint does not necessarily indicate that the user attempting to log in will be able to generate such a token.

Added in v1.7

type string

Required: The login type. This is supplied as the type when logging in.

{
  "flows": [
    {
      "type": "m.login.password"
    },
    {
      "get_login_token": true,
      "type": "m.login.token"
    }
  ]
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/login


Authenticates the user, and issues an access token they can use to authorize themself in subsequent requests.

If the client does not supply a device_id, the server must auto-generate one.

The returned access token must be associated with the device_id supplied by the client or generated by the server. The server may invalidate any access token previously associated with that device. See Relationship between access tokens and devices.

Rate-limited: Yes
Requires authentication: No

Request

Request body

Name Type Description
address string

Third-party identifier for the user. Deprecated in favour of identifier.

device_id string

ID of the client device. If this does not correspond to a known client device, a new device will be created. The given device ID must not be the same as a cross-signing key ID. The server will auto-generate a device_id if this is not specified.

identifier User identifier

Identification information for a user

initial_device_display_name string

A display name to assign to the newly-created device. Ignored if device_id corresponds to a known device.

medium string

When logging in using a third-party identifier, the medium of the identifier. Must be ’email’. Deprecated in favour of identifier.

password string

Required when type is m.login.password. The user’s password.

refresh_token boolean

If true, the client supports refresh tokens.

Added in v1.3

token string

Required when type is m.login.token. Part of Token-based login.

type string

Required: The login type being used.

This must be a type returned in one of the flows of the response of the GET /login endpoint, like m.login.password or m.login.token.

user string

The fully qualified user ID or just local part of the user ID, to log in. Deprecated in favour of identifier.

User identifier
Name Type Description
type string

Required: The type of identification. See Identifier types for supported values and additional property descriptions.

<Other properties>

Keys dependent on the identification type.

Request body example

{
  "identifier": {
    "type": "m.id.user",
    "user": "cheeky_monkey"
  },
  "initial_device_display_name": "Jungle Phone",
  "password": "ilovebananas",
  "type": "m.login.password"
}

Responses

Status Description
200 The user has been authenticated.
400 Part of the request was invalid. For example, the login type may not be recognised.
403

The login attempt failed. This can include one of the following error codes:

  • M_FORBIDDEN: The provided authentication data was incorrect or the requested device ID is the same as a cross-signing key ID.
  • M_USER_DEACTIVATED: The user has been deactivated.
429 This request was rate-limited.

200 response

Name Type Description
access_token string

Required: An access token for the account. This access token can then be used to authorize other requests.

device_id string

Required: ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified.

expires_in_ms integer

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.

Added in v1.3

home_server Server Name

The server_name of the homeserver on which the account has been registered.

Deprecated. Clients should extract the server_name from user_id (by splitting at the first colon) if they require it. Note also that homeserver is not spelt this way.

refresh_token string

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.

Added in v1.3

user_id User ID

Required: The fully-qualified Matrix ID for the account.

well_known Discovery Information

Optional client configuration provided by the server. If present, clients SHOULD use the provided object to reconfigure themselves, optionally validating the URLs within. This object takes the same form as the one returned from .well-known autodiscovery.

Discovery Information
Name Type Description
m.homeserver Homeserver Information

Required: Used by clients to discover homeserver information.

m.identity_server Identity Server Information

Used by clients to discover identity server information.

<Other properties>

Application-dependent keys using Java package naming convention.

Homeserver Information
Name Type Description
base_url URI

Required: The base URL for the homeserver for client-server connections.

Identity Server Information
Name Type Description
base_url URI

Required: The base URL for the identity server for client-server connections.

{
  "access_token": "abc123",
  "device_id": "GHTYAJCE",
  "expires_in_ms": 60000,
  "refresh_token": "def456",
  "user_id": "@cheeky_monkey:matrix.org",
  "well_known": {
    "m.homeserver": {
      "base_url": "https://example.org"
    },
    "m.identity_server": {
      "base_url": "https://id.example.org"
    }
  }
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "Bad login type."
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v1/login/get_token


Added in v1.7

Optional endpoint - the server is not required to implement this endpoint if it does not intend to use or support this functionality.

This API endpoint uses the User-Interactive Authentication API.

An already-authenticated client can call this endpoint to generate a single-use, time-limited, token for an unauthenticated client to log in with, becoming logged in as the same user which called this endpoint. The unauthenticated client uses the generated token in a m.login.token login flow with the homeserver.

Clients, both authenticated and unauthenticated, might wish to hide user interface which exposes this feature if the server is not offering it. Authenticated clients can check for support on a per-user basis with the m.get_login_token capability, while unauthenticated clients can detect server support by looking for an m.login.token login flow with get_login_token: true on GET /login.

In v1.7 of the specification, transmission of the generated token to an unauthenticated client is left as an implementation detail. Future MSCs such as MSC3906 might standardise a way to transmit the token between clients.

The generated token MUST only be valid for a single login, enforced by the server. Clients which intend to log in multiple devices must generate a token for each.

With other User-Interactive Authentication (UIA)-supporting endpoints, servers sometimes do not re-prompt for verification if the session recently passed UIA. For this endpoint, servers MUST always re-prompt the user for verification to ensure explicit consent is gained for each additional client.

Servers are encouraged to apply stricter than normal rate limiting to this endpoint, such as maximum of 1 request per minute.

Rate-limited: Yes
Requires authentication: Yes

Request

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  }
}

Responses

Status Description
200 The login token an unauthenticated client can use to log in as the requesting user.
400

The request was malformed, or the user does not have an ability to generate tokens for their devices, as implied by the User-Interactive Authentication API.

Clients should verify whether the user has an ability to call this endpoint with the m.get_login_token capability.

401 The homeserver requires additional authentication information.
429 This request was rate-limited.

200 response

Name Type Description
expires_in_ms integer

Required: The time remaining in milliseconds until the homeserver will no longer accept the token. 120000 (2 minutes) is recommended as a default.

login_token string

Required: The login token for the m.login.token login flow.

{
  "expires_in_ms": 120000,
  "login_token": "<opaque string>"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "An unknown error occurred"
}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/refresh


Added in v1.3

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.

Rate-limited: Yes
Requires authentication: No

Request

Request body

Name Type Description
refresh_token string

Required: The refresh token

Request body example

{
  "refresh_token": "some_token"
}

Responses

Status Description
200 A new access token and refresh token were generated.
401 The provided token was unknown, or has already been used.
429 This request was rate-limited.

200 response

Name Type Description
access_token string

Required: The new access token to use.

expires_in_ms integer

The lifetime of the access token, in milliseconds. If not given, the client can assume that the access token will not expire.

refresh_token string

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.

{
  "access_token": "a_new_token",
  "expires_in_ms": 60000,
  "refresh_token": "another_new_token"
}

401 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN_TOKEN",
  "error": "Soft logged out",
  "soft_logout": true
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/logout


Invalidates an existing access token, so that it can no longer be used for authorization. The device associated with the access token is also deleted. Device keys for the device are deleted alongside the device.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The access token used in the request was successfully invalidated.

200 response

{}

POST /_matrix/client/v3/logout/all


Invalidates all access tokens for a user, so that they can no longer be used for authorization. This includes the access token that made this request. All devices for the user are also deleted. Device keys for the device are deleted alongside the device.

This endpoint does not use the User-Interactive Authentication API because User-Interactive Authentication is designed to protect against attacks where the someone gets hold of a single access token then takes over the account. This endpoint invalidates all access tokens for the user, including the token used in the request, and therefore the attacker is unable to take over the account in this way.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The user’s access tokens were successfully invalidated.

200 response

{}

应用服务登录

[Added in v1.2]

应用服务可通过提供有效的应用服务令牌及其命名空间下的用户进行登录。

应用服务不一定需要以单独用户身份登录,可通过 身份断言 用应用服务令牌操作。但如需针对用户的令牌,可用下面 API。

该请求需通过应用服务 as_token认证(详见客户端认证令牌用法)。

使用方式如下:

{
  "type": "m.login.application_service",
  "identifier": {
    "type": "m.id.user",
    "user": "<user_id 或本地用户名>"
  }
}

如访问令牌无效、不属于应用服务,或该用户未注册,则主服务器返回错误码 M_FORBIDDEN

如 token 属于应用服务但用户 ID 不在其命名空间,返回错误码 M_EXCLUSIVE

登录 Fallback

客户端若无法识别登录流程,可用以下 fallback 登录 API:

GET /_matrix/static/client/login/

该端点返回含 JS 的 HTML 页面,可完整执行登录流程。登录成功后页面会调用 window.matrixLogin.onLogin(response),参数为 POST /_matrix/client/v3/login 的 JSON 响应体解析所得的 JS 对象。

[Added in v1.1] 可将非认证参数作为查询字符串提供至本端点,会在登录流程转发至实际登录 API。例如:

GET /_matrix/static/client/login/?device_id=GHTYAJCE

账户注册与管理

POST /_matrix/client/v3/account/deactivate


Deactivate the user’s account, removing all ability for the user to login again.

This API endpoint uses the User-Interactive Authentication API.

An access token should be submitted to this endpoint if the client has an active session.

The homeserver may change the flows available depending on whether a valid access token is provided.

Unlike other endpoints, this endpoint does not take an id_access_token parameter because the homeserver is expected to sign the request to the identity server instead.

Rate-limited: Yes
Requires authentication: Optional

Request

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

erase boolean

Whether the user would like their content to be erased as much as possible from the server.

Erasure means that any users (or servers) which join the room after the erasure request are served redacted copies of the events sent by this account. Users which had visibility on those events prior to the erasure are still able to see unredacted copies. No redactions are sent and the erasure request is not shared over federation, so other servers might still serve unredacted copies.

The server should additionally erase any non-event data associated with the user, such as account data and contact 3PIDs.

Defaults to false if not present.

Added in v1.10

id_server string

The identity server to unbind all of the user’s 3PIDs from. If not provided, the homeserver MUST use the id_server that was originally use to bind each identifier. If the homeserver does not know which id_server that was, it must return an id_server_unbind_result of no-support.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "id_server": "example.org"
}

Responses

Status Description
200 The account has been deactivated.
401 The homeserver requires additional authentication information.
429 This request was rate-limited.

200 response

Name Type Description
id_server_unbind_result string

Required: An indicator as to whether or not the homeserver was able to unbind the user’s 3PIDs from the identity server(s). success indicates that all identifiers have been unbound from the identity server while no-support indicates that one or more identifiers failed to unbind due to the identity server refusing the request or the homeserver being unable to determine an identity server to unbind from. This must be success if the homeserver has no identifiers to unbind for the user.

One of: [success, no-support].

{
  "id_server_unbind_result": "success"
}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/account/password


Changes the password for an account on this homeserver.

This API endpoint uses the User-Interactive Authentication API to ensure the user changing the password is actually the owner of the account.

An access token should be submitted to this endpoint if the client has an active session.

The homeserver may change the flows available depending on whether a valid access token is provided. The homeserver SHOULD NOT revoke the access token provided in the request. Whether other access tokens for the user are revoked depends on the request parameters.

Rate-limited: Yes
Requires authentication: Optional

Request

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

logout_devices boolean

Whether the user’s other access tokens, and their associated devices, should be revoked if the request succeeds. Defaults to true.

When false, the server can still take advantage of the soft logout method for the user’s remaining devices.

new_password string

Required: The new password for the account.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "logout_devices": true,
  "new_password": "ihatebananas"
}

Responses

Status Description
200 The password has been changed.
401 The homeserver requires additional authentication information.
429 This request was rate-limited.

200 response

{}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/account/password/email/requestToken


The homeserver must check that the given email address is associated with an account on this homeserver. This API should be used to request validation tokens when authenticating for the /account/password endpoint.

This API’s parameters and response are identical to that of the /register/email/requestToken endpoint, except that M_THREEPID_NOT_FOUND may be returned if no account matching the given email address could be found. The server may instead send an email to the given address prompting the user to create an account. M_THREEPID_IN_USE may not be returned.

The homeserver should validate the email itself, either by sending a validation email itself or by using a service it has control over.

Rate-limited: No
Requires authentication: No

Request

Request body

Name Type Description
client_secret string

Required: A unique string generated by the client, and used to identify the validation attempt. It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed 255 characters and it must not be empty.

email Email Address

Required: The email address to validate.

id_access_token string

An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

Required if an id_server is supplied.

id_server string

The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification.

This parameter is deprecated with a plan to be removed in a future specification version for /account/password and /register requests.

next_link URI

Optional. When the validation is completed, the identity server will redirect the user to this URL. This option is ignored when submitting 3PID validation information through a POST request.

send_attempt integer

Required: The server will only send an email if the send_attempt is a number greater than the most recent one which it has seen, scoped to that email + client_secret pair. This is to avoid repeatedly sending the same email in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new email (e.g. a reminder) to be sent. If they do not, the server should respond with success but not resend the email.

Request body example

{
  "client_secret": "monkeys_are_GREAT",
  "email": "alice@example.org",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "send_attempt": 1
}

Responses

Status Description
200 An email was sent to the given address.
400 The referenced third-party identifier is not recognised by the homeserver, or the request was invalid. The error code M_SERVER_NOT_TRUSTED can be returned if the server does not trust/support the identity server provided in the request.
403 The homeserver does not allow the third-party identifier as a contact option.

200 response

RequestTokenResponse
Name Type Description
sid string

Required: The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty.

submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_NOT_FOUND",
  "error": "Email not found"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_DENIED",
  "error": "Third-party identifier is not allowed"
}

POST /_matrix/client/v3/account/password/msisdn/requestToken


The homeserver must check that the given phone number is associated with an account on this homeserver. This API should be used to request validation tokens when authenticating for the /account/password endpoint.

This API’s parameters and response are identical to that of the /register/msisdn/requestToken endpoint, except that M_THREEPID_NOT_FOUND may be returned if no account matching the given phone number could be found. The server may instead send the SMS to the given phone number prompting the user to create an account. M_THREEPID_IN_USE may not be returned.

The homeserver should validate the phone number itself, either by sending a validation message itself or by using a service it has control over.

Rate-limited: No
Requires authentication: No

Request

Request body

Name Type Description
client_secret string

Required: A unique string generated by the client, and used to identify the validation attempt. It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed 255 characters and it must not be empty.

country string

Required: The two-letter uppercase ISO-3166-1 alpha-2 country code that the number in phone_number should be parsed as if it were dialled from.

id_access_token string

An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

Required if an id_server is supplied.

id_server string

The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification.

This parameter is deprecated with a plan to be removed in a future specification version for /account/password and /register requests.

next_link URI

Optional. When the validation is completed, the identity server will redirect the user to this URL. This option is ignored when submitting 3PID validation information through a POST request.

phone_number string

Required: The phone number to validate.

send_attempt integer

Required: The server will only send an SMS if the send_attempt is a number greater than the most recent one which it has seen, scoped to that country + phone_number + client_secret triple. This is to avoid repeatedly sending the same SMS in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new SMS (e.g. a reminder) to be sent.

Request body example

{
  "client_secret": "monkeys_are_GREAT",
  "country": "GB",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "phone_number": "07700900001",
  "send_attempt": 1
}

Responses

Status Description
200 An SMS message was sent to the given phone number.
400 The referenced third-party identifier is not recognised by the homeserver, or the request was invalid. The error code M_SERVER_NOT_TRUSTED can be returned if the server does not trust/support the identity server provided in the request.
403 The homeserver does not allow the third-party identifier as a contact option.

200 response

RequestTokenResponse
Name Type Description
sid string

Required: The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty.

submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_NOT_FOUND",
  "error": "Phone number not found"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_DENIED",
  "error": "Third-party identifier is not allowed"
}

POST /_matrix/client/v3/register


This API endpoint uses the User-Interactive Authentication API, except in the cases where a guest account is being registered.

Register for an account on this homeserver.

There are two kinds of user account:

  • user accounts. These accounts may use the full API described in this specification.

  • guest accounts. These accounts may have limited permissions and may not be supported by all servers.

If registration is successful, this endpoint will issue an access token the client can use to authorize itself in subsequent requests.

If the client does not supply a device_id, the server must auto-generate one.

The server SHOULD register an account with a User ID based on the username provided, if any. Note that the grammar of Matrix User ID localparts is restricted, so the server MUST either map the provided username onto a user_id in a logical manner, or reject any username which does not comply to the grammar with M_INVALID_USERNAME.

Matrix clients MUST NOT assume that localpart of the registered user_id matches the provided username.

The returned access token must be associated with the device_id supplied by the client or generated by the server. The server may invalidate any access token previously associated with that device. See Relationship between access tokens and devices.

When registering a guest account, all parameters in the request body with the exception of initial_device_display_name MUST BE ignored by the server. The server MUST pick a device_id for the account regardless of input.

Any user ID returned by this API must conform to the grammar given in the Matrix specification.

Rate-limited: Yes
Requires authentication: No

Request

Request parameters

query parameters
Name Type Description
kind string

The kind of account to register. Defaults to user.

One of: [guest, user].

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API. Note that this information is not used to define how the registered user should be authenticated, but is instead used to authenticate the register call itself.

device_id string

ID of the client device. If this does not correspond to a known client device, a new device will be created. The server will auto-generate a device_id if this is not specified.

inhibit_login boolean

If true, an access_token and device_id should not be returned from this call, therefore preventing an automatic login. Defaults to false.

initial_device_display_name string

A display name to assign to the newly-created device. Ignored if device_id corresponds to a known device.

password string

The desired password for the account.

refresh_token boolean

If true, the client supports refresh tokens.

Added in v1.3

username string

The basis for the localpart of the desired Matrix ID. If omitted, the homeserver MUST generate a Matrix ID local part.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "device_id": "GHTYAJCE",
  "initial_device_display_name": "Jungle Phone",
  "password": "ilovebananas",
  "username": "cheeky_monkey"
}

Responses

Status Description
200 The account has been registered.
400

Part of the request was invalid. This may include one of the following error codes:

  • M_USER_IN_USE : The desired user ID is already taken.
  • M_INVALID_USERNAME : The desired user ID is not a valid user name.
  • M_EXCLUSIVE : The desired user ID is in the exclusive namespace claimed by an application service.

These errors may be returned at any stage of the registration process, including after authentication if the requested user ID was registered whilst the client was performing authentication.

Homeservers MUST perform the relevant checks and return these codes before performing User-Interactive Authentication, although they may also return them after authentication is completed if, for example, the requested user ID was registered whilst the client was performing authentication.

401 The homeserver requires additional authentication information.
403 The homeserver does not permit registering the account. This response can be used to identify that a particular kind of account is not allowed, or that registration is generally not supported by the homeserver.
429 This request was rate-limited.

200 response

Name Type Description
access_token string

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.

device_id string

ID of the registered device. Will be the same as the corresponding parameter in the request, if one was specified. Required if the inhibit_login option is false.

expires_in_ms integer

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.

Added in v1.3

home_server Server Name

The server_name of the homeserver on which the account has been registered.

Deprecated. Clients should extract the server_name from user_id (by splitting at the first colon) if they require it. Note also that homeserver is not spelt this way.

refresh_token string

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.

Added in v1.3

user_id User ID

Required: The fully-qualified Matrix user ID (MXID) that has been registered.

Any user ID returned by this API must conform to the grammar given in the Matrix specification.

{
  "access_token": "abc123",
  "device_id": "GHTYAJCE",
  "user_id": "@cheeky_monkey:matrix.org"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_USER_IN_USE",
  "error": "Desired user ID is already taken."
}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Registration is disabled"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/register/available


Checks to see if a username is available, and valid, for the server.

The server should check to ensure that, at the time of the request, the username requested is available for use. This includes verifying that an application service has not claimed the username and that the username fits the server’s desired requirements (for example, a server could dictate that it does not permit usernames with underscores).

Matrix clients may wish to use this API prior to attempting registration, however the clients must also be aware that using this API does not normally reserve the username. This can mean that the username becomes unavailable between checking its availability and attempting to register it.

Rate-limited: Yes
Requires authentication: No

Request

Request parameters

query parameters
Name Type Description
username string

Required: The username to check the availability of.


Responses

Status Description
200 The username is available
400

Part of the request was invalid or the username is not available. This may include one of the following error codes:

  • M_USER_IN_USE : The desired username is already taken.
  • M_INVALID_USERNAME : The desired username is not a valid user name.
  • M_EXCLUSIVE : The desired username is in the exclusive namespace claimed by an application service.
429 This request was rate-limited.

200 response

Name Type Description
available boolean

A flag to indicate that the username is available. This should always be true when the server replies with 200 OK.

{
  "available": true
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_USER_IN_USE",
  "error": "Desired user ID is already taken."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/register/email/requestToken


The homeserver must check that the given email address is not already associated with an account on this homeserver. The homeserver should validate the email itself, either by sending a validation email itself or by using a service it has control over.

Rate-limited: No
Requires authentication: No

Request

Request body

Name Type Description
client_secret string

Required: A unique string generated by the client, and used to identify the validation attempt. It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed 255 characters and it must not be empty.

email Email Address

Required: The email address to validate.

id_access_token string

An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

Required if an id_server is supplied.

id_server string

The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification.

This parameter is deprecated with a plan to be removed in a future specification version for /account/password and /register requests.

next_link URI

Optional. When the validation is completed, the identity server will redirect the user to this URL. This option is ignored when submitting 3PID validation information through a POST request.

send_attempt integer

Required: The server will only send an email if the send_attempt is a number greater than the most recent one which it has seen, scoped to that email + client_secret pair. This is to avoid repeatedly sending the same email in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new email (e.g. a reminder) to be sent. If they do not, the server should respond with success but not resend the email.

Request body example

{
  "client_secret": "monkeys_are_GREAT",
  "email": "alice@example.org",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "send_attempt": 1
}

Responses

Status Description
200 An email has been sent to the specified address. Note that this may be an email containing the validation token or it may be informing the user of an error.
400

Part of the request was invalid. This may include one of the following error codes:

  • M_THREEPID_IN_USE : The email address is already registered to an account on this server. However, if the homeserver has the ability to send email, it is recommended that the server instead send an email to the user with instructions on how to reset their password. This prevents malicious parties from being able to determine if a given email address has an account on the homeserver in question.
  • M_SERVER_NOT_TRUSTED : The id_server parameter refers to an identity server that is not trusted by this homeserver.
403 The homeserver does not permit the address to be bound.

200 response

RequestTokenResponse
Name Type Description
sid string

Required: The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty.

submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_IN_USE",
  "error": "The specified address is already in use"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_DENIED",
  "error": "Third-party identifier is not allowed"
}

POST /_matrix/client/v3/register/msisdn/requestToken


The homeserver must check that the given phone number is not already associated with an account on this homeserver. The homeserver should validate the phone number itself, either by sending a validation message itself or by using a service it has control over.

Rate-limited: No
Requires authentication: No

Request

Request body

Name Type Description
client_secret string

Required: A unique string generated by the client, and used to identify the validation attempt. It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed 255 characters and it must not be empty.

country string

Required: The two-letter uppercase ISO-3166-1 alpha-2 country code that the number in phone_number should be parsed as if it were dialled from.

id_access_token string

An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

Required if an id_server is supplied.

id_server string

The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification.

This parameter is deprecated with a plan to be removed in a future specification version for /account/password and /register requests.

next_link URI

Optional. When the validation is completed, the identity server will redirect the user to this URL. This option is ignored when submitting 3PID validation information through a POST request.

phone_number string

Required: The phone number to validate.

send_attempt integer

Required: The server will only send an SMS if the send_attempt is a number greater than the most recent one which it has seen, scoped to that country + phone_number + client_secret triple. This is to avoid repeatedly sending the same SMS in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new SMS (e.g. a reminder) to be sent.

Request body example

{
  "client_secret": "monkeys_are_GREAT",
  "country": "GB",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "phone_number": "07700900001",
  "send_attempt": 1
}

Responses

Status Description
200 An SMS message has been sent to the specified phone number. Note that this may be an SMS message containing the validation token or it may be informing the user of an error.
400

Part of the request was invalid. This may include one of the following error codes:

  • M_THREEPID_IN_USE : The phone number is already registered to an account on this server. However, if the homeserver has the ability to send SMS message, it is recommended that the server instead send an SMS message to the user with instructions on how to reset their password. This prevents malicious parties from being able to determine if a given phone number has an account on the homeserver in question.
  • M_SERVER_NOT_TRUSTED : The id_server parameter refers to an identity server that is not trusted by this homeserver.
403 The homeserver does not permit the address to be bound.

200 response

RequestTokenResponse
Name Type Description
sid string

Required: The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty.

submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_IN_USE",
  "error": "The specified address is already in use"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_DENIED",
  "error": "Third-party identifier is not allowed"
}

密码管理注意事项

客户端强制密码的足够复杂性,建议至少包含小写字母、大写字母、数字和符号,最少 8 位。服务器可拒绝弱密码,并返回 M_WEAK_PASSWORD 错误码。

账户锁定

[Added in v1.12]

服务器管理员可对帐号加锁(如出于安全原因),锁定行为非破坏性,可后续解锁。下述定义了客户端与服务器的行为,具体加锁/解锁方式为实现细节。

账户锁定时,服务器必须对除下列 API 外的所有客户端-服务器 API 返回 401 错误、错误码 M_USER_LOCKED 并设置 soft_logout

服务器可在 error 字段告知锁定原因。

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "errcode": "M_USER_LOCKED",
  "error": "本账户已被锁定",
  "soft_logout": true
}

服务器不应在账户锁定时立即吊销访问令牌,除非客户端主动调用上述登出端点。这样可以确保账户解锁后用户无需重新登录。

收到 M_USER_LOCKED 错误时,客户端应保留会话加密等信息,并提示用户帐户已被锁定。锁定期间应隐藏正常 UI 禁止使用账户,但以限流方式持续轮询 /sync 等接口以检测解锁。

如需申诉可使用服务器联系方式发现

账户停用

[Added in v1.13]

服务器管理员可停用用户账户以防止进一步操作。其效果类似锁定,但不会导致客户端丢失会话状态。停用可逆,不同于注销账号。

可用操作范围为服务器实现细节,但建议至少允许:

一般请求如 /send/{eventType} 可根据请求参数决定是否允许,如允许发送撤回事件但不允许普通消息。

如房间用作管理员与被停用用户沟通通道,建议允许用户在该房间中发言。不想让其接收通知的管理员可考虑锁定账户

其它被禁止的建议操作:

  • 加入或敲门进入房间
  • 接受或发送邀请
  • 向房间发送消息
  • 修改资料
  • 撤回他人消息(如房间权限允许)

如客户端试图在停用时操作,服务器必须以 403 Forbidden、错误码 M_USER_SUSPENDED 响应:

HTTP/1.1 403 Forbidden
Content-Type: application/json
{
  "errcode": "M_USER_SUSPENDED",
  "error": "您在账号停用期间无法执行此操作。"
}

有关停用/取消停用 API 暂未纳入本规范,属实现细节。

添加账户管理员联系信息

主服务器可独立保存一些用于管理的联系信息。此信息独立于身份服务器,可以绑定至身份服务器。

本节涉及“添加”“绑定”概念。添加(或移除)指未绑定至身份服务器的标识符;绑定(或解绑)指服务端绑定于身份服务器。取决于上下文,标识符可同时添加和绑定。

GET /_matrix/client/v3/account/3pid


Gets a list of the third-party identifiers that the homeserver has associated with the user’s account.

This is not the same as the list of third-party identifiers bound to the user’s Matrix ID in identity servers.

Identifiers in this list may be used by the homeserver as, for example, identifiers that it will accept to reset the user’s account password.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The lookup was successful.

200 response

Name Type Description
threepids [Third-party identifier]
Third-party identifier
Name Type Description
added_at integer

Required: The timestamp, in milliseconds, when the homeserver associated the third-party identifier with the user.

address string

Required: The third-party identifier address.

medium string

Required: The medium of the third-party identifier.

One of: [email, msisdn].

validated_at integer

Required: The timestamp, in milliseconds, when the identifier was validated by the identity server.

{
  "threepids": [
    {
      "added_at": 1535336848756,
      "address": "monkey@banana.island",
      "medium": "email",
      "validated_at": 1535176800000
    }
  ]
}

POST /_matrix/client/v3/account/3pid


This API is deprecated and will be removed from a future release.

Adds contact information to the user’s account.

This endpoint is deprecated in favour of the more specific /3pid/add and /3pid/bind endpoints.

Note: Previously this endpoint supported a bind parameter. This parameter has been removed, making this endpoint behave as though it was false. This results in this endpoint being an equivalent to /3pid/bind rather than dual-purpose.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
three_pid_creds ThreePidCredentials

Required: The third-party credentials to associate with the account.

ThreePidCredentials
Name Type Description
client_secret string

Required: The client secret used in the session with the identity server.

id_access_token string

Required: An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

id_server string

Required: The identity server to use.

sid string

Required: The session identifier given by the identity server.

Request body example

{
  "three_pid_creds": {
    "client_secret": "d0nt-T3ll",
    "id_access_token": "abc123_OpaqueString",
    "id_server": "matrix.org",
    "sid": "abc123987"
  }
}

Responses

Status Description
200 The addition was successful.
403 The credentials could not be verified with the identity server.

200 response

Name Type Description
submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "submit_url": "https://example.org/path/to/submitToken"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_AUTH_FAILED",
  "error": "The third-party credentials could not be verified by the identity server."
}

POST /_matrix/client/v3/account/3pid/add


This API endpoint uses the User-Interactive Authentication API.

Adds contact information to the user’s account. Homeservers should use 3PIDs added through this endpoint for password resets instead of relying on the identity server.

Homeservers should prevent the caller from adding a 3PID to their account if it has already been added to another user’s account on the homeserver.

Rate-limited: Yes
Requires authentication: Yes

Request

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

client_secret string

Required: The client secret used in the session with the homeserver.

sid string

Required: The session identifier given by the homeserver.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "client_secret": "d0nt-T3ll",
  "sid": "abc123987"
}

Responses

Status Description
200 The addition was successful.
401 The homeserver requires additional authentication information.
429 This request was rate-limited.

200 response

{}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/account/3pid/bind


Binds a 3PID to the user’s account through the specified identity server.

Homeservers should not prevent this request from succeeding if another user has bound the 3PID. Homeservers should simply proxy any errors received by the identity server to the caller.

Homeservers should track successful binds so they can be unbound later.

Rate-limited: Yes
Requires authentication: Yes

Request

Request body

Name Type Description
client_secret string

Required: The client secret used in the session with the identity server.

id_access_token string

Required: An access token previously registered with the identity server.

id_server string

Required: The identity server to use.

sid string

Required: The session identifier given by the identity server.

Request body example

{
  "client_secret": "d0nt-T3ll",
  "id_access_token": "abc123_OpaqueString",
  "id_server": "example.org",
  "sid": "abc123987"
}

Responses

Status Description
200 The addition was successful.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/account/3pid/delete


Removes a third-party identifier from the user’s account. This might not cause an unbind of the identifier from the identity server.

Unlike other endpoints, this endpoint does not take an id_access_token parameter because the homeserver is expected to sign the request to the identity server instead.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
address string

Required: The third-party address being removed.

id_server string

The identity server to unbind from. If not provided, the homeserver MUST use the id_server the identifier was added through. If the homeserver does not know the original id_server, it MUST return a id_server_unbind_result of no-support.

medium string

Required: The medium of the third-party identifier being removed.

One of: [email, msisdn].

Request body example

{
  "address": "example@example.org",
  "id_server": "example.org",
  "medium": "email"
}

Responses

Status Description
200 The homeserver has disassociated the third-party identifier from the user.

200 response

Name Type Description
id_server_unbind_result string

Required: An indicator as to whether or not the homeserver was able to unbind the 3PID from the identity server. success indicates that the identity server has unbound the identifier whereas no-support indicates that the identity server refuses to support the request or the homeserver was not able to determine an identity server to unbind from.

One of: [no-support, success].

{
  "id_server_unbind_result": "success"
}

POST /_matrix/client/v3/account/3pid/email/requestToken


The homeserver must check that the given email address is not already associated with an account on this homeserver. This API should be used to request validation tokens when adding an email address to an account. This API’s parameters and response are identical to that of the /register/email/requestToken endpoint. The homeserver should validate the email itself, either by sending a validation email itself or by using a service it has control over.

Rate-limited: No
Requires authentication: No

Request

Request body

Name Type Description
client_secret string

Required: A unique string generated by the client, and used to identify the validation attempt. It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed 255 characters and it must not be empty.

email Email Address

Required: The email address to validate.

id_access_token string

An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

Required if an id_server is supplied.

id_server string

The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification.

This parameter is deprecated with a plan to be removed in a future specification version for /account/password and /register requests.

next_link URI

Optional. When the validation is completed, the identity server will redirect the user to this URL. This option is ignored when submitting 3PID validation information through a POST request.

send_attempt integer

Required: The server will only send an email if the send_attempt is a number greater than the most recent one which it has seen, scoped to that email + client_secret pair. This is to avoid repeatedly sending the same email in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new email (e.g. a reminder) to be sent. If they do not, the server should respond with success but not resend the email.

Request body example

{
  "client_secret": "monkeys_are_GREAT",
  "email": "alice@example.org",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "send_attempt": 1
}

Responses

Status Description
200 An email was sent to the given address. Note that this may be an email containing the validation token or it may be informing the user of an error.
400

The third-party identifier is already in use on the homeserver, or the request was invalid. Error codes that can be returned are:

  • M_THREEPID_IN_USE: The email supplied cannot be bound because is is already associated with a different Matrix ID.
  • M_SERVER_NOT_TRUSTED: The server does not trust/support the identity server provided in the request.
  • M_THREEPID_MEDIUM_NOT_SUPPORTED: The homeserver does not support adding email addresses.
  • M_INVALID_PARAM: The email address given was not valid.
403 The homeserver does not allow the third-party identifier as a contact option.

200 response

RequestTokenResponse
Name Type Description
sid string

Required: The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty.

submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_IN_USE",
  "error": "Third-party identifier already in use"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_DENIED",
  "error": "Third-party identifier is not allowed"
}

POST /_matrix/client/v3/account/3pid/msisdn/requestToken


The homeserver must check that the given phone number is not already associated with an account on this homeserver. This API should be used to request validation tokens when adding a phone number to an account. This API’s parameters and response are identical to that of the /register/msisdn/requestToken endpoint. The homeserver should validate the phone number itself, either by sending a validation message itself or by using a service it has control over.

Rate-limited: No
Requires authentication: No

Request

Request body

Name Type Description
client_secret string

Required: A unique string generated by the client, and used to identify the validation attempt. It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed 255 characters and it must not be empty.

country string

Required: The two-letter uppercase ISO-3166-1 alpha-2 country code that the number in phone_number should be parsed as if it were dialled from.

id_access_token string

An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

Required if an id_server is supplied.

id_server string

The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification.

This parameter is deprecated with a plan to be removed in a future specification version for /account/password and /register requests.

next_link URI

Optional. When the validation is completed, the identity server will redirect the user to this URL. This option is ignored when submitting 3PID validation information through a POST request.

phone_number string

Required: The phone number to validate.

send_attempt integer

Required: The server will only send an SMS if the send_attempt is a number greater than the most recent one which it has seen, scoped to that country + phone_number + client_secret triple. This is to avoid repeatedly sending the same SMS in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new SMS (e.g. a reminder) to be sent.

Request body example

{
  "client_secret": "monkeys_are_GREAT",
  "country": "GB",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "phone_number": "07700900001",
  "send_attempt": 1
}

Responses

Status Description
200 An SMS message was sent to the given phone number.
400

The third-party identifier is already in use on the homeserver, or the request was invalid. Error codes that can be returned are:

  • M_THREEPID_IN_USE: The phone number supplied cannot be bound because is is already associated with a different Matrix ID.
  • M_SERVER_NOT_TRUSTED: The server does not trust/support the identity server
  • M_THREEPID_MEDIUM_NOT_SUPPORTED: The homeserver does not support adding phone numbers.
  • M_INVALID_PARAM: The phone number given was not valid.
403 The homeserver does not allow the third-party identifier as a contact option.

200 response

RequestTokenResponse
Name Type Description
sid string

Required: The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty.

submit_url URI

An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity Service API’s POST /validate/email/submitToken endpoint (without the requirement for an access token). The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client.

If this field is not present, the client can assume that verification will happen without the client’s involvement provided the homeserver advertises this specification version in the /versions response (ie: r0.5.0).

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_IN_USE",
  "error": "Third-party identifier already in use"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_THREEPID_DENIED",
  "error": "Third-party identifier is not allowed"
}

POST /_matrix/client/v3/account/3pid/unbind


Removes a user’s third-party identifier from the provided identity server without removing it from the homeserver.

Unlike other endpoints, this endpoint does not take an id_access_token parameter because the homeserver is expected to sign the request to the identity server instead.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
address string

Required: The third-party address being removed.

id_server string

The identity server to unbind from. If not provided, the homeserver MUST use the id_server the identifier was added through. If the homeserver does not know the original id_server, it MUST return a id_server_unbind_result of no-support.

medium string

Required: The medium of the third-party identifier being removed.

One of: [email, msisdn].

Request body example

{
  "address": "example@example.org",
  "id_server": "example.org",
  "medium": "email"
}

Responses

Status Description
200 The identity server has disassociated the third-party identifier from the user.

200 response

Name Type Description
id_server_unbind_result string

Required: An indicator as to whether or not the identity server was able to unbind the 3PID. success indicates that the identity server has unbound the identifier whereas no-support indicates that the identity server refuses to support the request or the homeserver was not able to determine an identity server to unbind from.

One of: [no-support, success].

{
  "id_server_unbind_result": "success"
}

当前账户信息

GET /_matrix/client/v3/account/whoami


Gets information about the owner of a given access token.

Note that, as with the rest of the Client-Server API, Application Services may masquerade as users within their namespace by giving a user_id query parameter. In this situation, the server should verify that the given user_id is registered by the appservice, and return it in the response body.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The token belongs to a known user.
401 The token is not recognised
403 The appservice cannot masquerade as the user or has not registered them.
429 This request was rate-limited.

200 response

Name Type Description
device_id string

Device ID associated with the access token. If no device is associated with the access token (such as in the case of application services) then this field can be omitted. Otherwise this is required.

Added in v1.1

is_guest boolean

When true, the user is a Guest User. When not present or false, the user is presumed to be a non-guest user.

Added in v1.2

user_id User ID

Required: The user ID that owns the access token.

{
  "device_id": "ABC1234",
  "user_id": "@joe:example.org"
}

401 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN_TOKEN",
  "error": "Unrecognised access token."
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Application service has not registered this user."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

关于身份服务器的说明

Matrix 身份服务器存储用户第三方标识符(如邮箱、手机)与用户 ID 的绑定。用户确定身份服务器后,所有客户端都应使用该身份服务器。

客户端可通过账户数据事件 m.identity_server 得知用户所选身份服务器(见本章下文)。客户端在检测到该数据(已/未出现)前不要请求身份服务器,如有 base_url 字段则使用该身份服务器,否则用默认值,且不应在为用户设置身份服务器前将默认值写入账户数据。

客户端应监听 m.identity_server 事件变更,并同步其使用的身份服务器。

如客户端允许用户设置身份服务器,必须更新 m.identity_serverbase_urlnull 时应视为不希望启用身份服务器,相关功能禁用。

客户端不应为缺少该事件的用户迁移补默认身份服务器,除非用户主动设置。即,用户未设置相关数据时,客户端不应主动写入默认身份服务器。

m.identity_server


Persists the user’s preferred identity server, or preference to not use an identity server at all, in the user’s account data.

Event type: Message event

Content

Name Type Description
base_url URI|null

The URL of the identity server the user prefers to use, or null if the user does not want to use an identity server. This value is similar in structure to the base_url for identity servers in the .well-known/matrix/client schema.

Examples

{
  "content": {
    "base_url": "https://example.org"
  },
  "type": "m.identity_server"
}

能力协商

主服务器可能不支持部分功能,客户端需有查询主服务器能力的机制。例如主服务器采用外部认证,无法支持密码变更。

通过此机制声明的能力旨在描述 API 内可选功能,或与用户/服务器状态相关功能。不用于实验性功能,实验性或不稳定功能应由 /versions 公布。

合理能力如:

  • 是否支持用户在线状态
  • 是否支持可选功能如用户目录或房间目录
  • 服务器对客户端速率限制、文件类型限制

不应声明为能力的有:

  • 是否支持规范中处于 unstable 状态的功能
  • 媒体文件大小(已由 /config API 管理)
  • 可选编码/传输方式

能力以 m. 为前缀为 Matrix 规范保留,其它命名建议采用 Java 包命名风格。具体支持能力见下。

GET /_matrix/client/v3/capabilities


Gets information about the server’s supported feature set and other relevant capabilities.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The capabilities of the server.
429 This request was rate-limited.

200 response

Name Type Description
capabilities Capabilities

Required: The custom capabilities the server supports, using the Java package naming convention.

Capabilities
Name Type Description
m.3pid_changes BooleanCapability

Capability to indicate if the user can change 3PID associations on their account.

m.change_password BooleanCapability

Capability to indicate if the user can change their password.

m.get_login_token BooleanCapability

Capability to indicate if the user can generate tokens to log further clients into their account.

m.room_versions RoomVersionsCapability

The room versions the server supports.

m.set_avatar_url BooleanCapability

Capability to indicate if the user can change their avatar.

m.set_displayname BooleanCapability

Capability to indicate if the user can change their display name.

<Other properties>

Application-dependent keys using the Common Namespaced Identifier Grammar.

BooleanCapability
Name Type Description
enabled boolean

Required: True if the user can perform the action, false otherwise.

RoomVersionsCapability
Name Type Description
available {string: string}

Required: A detailed description of the room versions the server supports.

default string

Required: The default room version the server is using for new rooms.

{
  "capabilities": {
    "com.example.custom.ratelimit": {
      "max_requests_per_hour": 600
    },
    "m.change_password": {
      "enabled": false
    },
    "m.room_versions": {
      "available": {
        "1": "stable",
        "2": "stable",
        "3": "unstable",
        "test-version": "unstable"
      },
      "default": "1"
    }
  }
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

m.change_password 能力

本能力含 enabled 字段,表示用户能否调用 /account/password API 修改密码。不出现时默认允许修改密码。出现且 enabled 为假时,客户端应提示用户无法修改密码。

示例:

{
  "capabilities": {
    "m.change_password": {
      "enabled": false
    }
  }
}

m.room_versions 能力

描述服务器支持的默认及可用房间版本与稳定性级别。客户端可用以判定房间是否需升级。

示例:

{
  "capabilities": {
    "m.room_versions": {
      "default": "1",
      "available": {
        "1": "stable",
        "2": "stable",
        "3": "unstable",
        "custom-version": "unstable"
      }
    }
  }
}

本能力参考房间版本。未被 available 标为 stable 的统统视为 unstable。例如 future-stable 也算 unstable

default 为服务器新建房间采用的版本。客户端应引导有权限用户将unstable房间升级为 default 版本。

如无本能力,客户端应以 "1" 作为默认和唯一可用稳定房间版本。

m.set_displayname 能力

本能力含 enabled 字段,标识用户能否通过资料接口修改昵称。若禁用,常为目录服务(如 LDAP)映射帐号。

此能力常与 m.set_avatar_url 成对出现。

如不出现,默认允许修改昵称。

示例:

{
  "capabilities": {
    "m.set_displayname": {
      "enabled": false
    }
  }
}

m.set_avatar_url 能力

本能力唯一 enabled 字段,标识用户可否通过资料接口修改头像。典型禁用场景为外部服务(如 LDAP)账号同步。

m.set_displayname 能力常成对。

缺省时默认可修改头像。

示例:

{
  "capabilities": {
    "m.set_avatar_url": {
      "enabled": false
    }
  }
}

m.3pid_changes 能力

本能力唯一字段 enabled,标识用户是否能添加、删除或修改自己的三方账号。注意仅作用于管理员联系信息接口,不影响身份服务端点。禁用通常为目录服务类(如 LDAP)账号的自动同步。

缺省时默认允许修改。

示例:

{
  "capabilities": {
    "m.3pid_changes": {
      "enabled": false
    }
  }
}

m.get_login_token 能力

本能力唯一字段 enabled,标识用户是否可通过 POST /login/get_token 生成一次性登陆令牌,用于免认证客户端登陆。

缺省时,客户端应认为用户不能生成此类令牌。

示例:

{
  "capabilities": {
    "m.get_login_token": {
      "enabled": false
    }
  }
}

过滤

过滤器可在服务器端创建,作为参数传递到支持事件返回的 API 里,这会影响 API 返回的数据内容。只有部分 API 支持过滤器。

房间成员延迟加载

成员事件数量巨大时占用资源较大。为节省资源,客户端可启用“延迟加载”,服务器仅发送与客户端相关的成员事件。

延迟加载作为优化不是绝对精确的,服务器可以为简化实现而多发部分事件,但应尽量减少冗余。

在过滤器层面,通过设定 RoomEventFilterlazy_load_members 开启延迟加载。启用后,支持该特性的端点仅返回事件发送方的成员事件。例如带延迟加载的 /sync 仅返回时间线内发生事件相关的发送者成员事件。

处理事件序列(如循环调用 /sync 或分页 /messages)时,事件块发送用户可能重叠。服务器可以假设客户端会保留已接收成员事件,对没变化的用户成员事件不必重发(称为“冗余成员事件”)。客户端如需总是收到全部冗余成员事件,可设 include_redundant_members 为 true。

推荐用法如下:

  • 客户端初次同步 /sync 启用延迟加载,仅获取当前事件的发送人成员事件。
  • 如需展示房间成员列表,可调用 /members,参数 ?at 设为 /sync 的 from token。房间成员列表随后跟随增量 /sync 维护。
  • 不支持成员补全可通过查询房间状态或 /profile 按需获取。

支持延迟加载的端点有:

API 端点

POST /_matrix/client/v3/user/{userId}/filter


Uploads a new filter definition to the homeserver. Returns a filter ID that may be used in future requests to restrict which events are returned to the client.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The id of the user uploading the filter. The access token must be authorized to make requests for this user id.

Request body

Filter
Name Type Description
account_data EventFilter

The user account data that isn’t associated with rooms to include.

event_fields [string]

List of event fields to include. If this list is absent then all fields are included. The entries are dot-separated paths for each property to include. So [‘content.body’] will include the ‘body’ field of the ‘content’ object. A server may include more fields than were requested.

event_format string

The format to use for events. ‘client’ will return the events in a format suitable for clients. ‘federation’ will return the raw event as received over federation. The default is ‘client’.

One of: [client, federation].

presence EventFilter

The presence updates to include.

room RoomFilter

Filters to be applied to room data.

EventFilter
Name Type Description
limit integer

The maximum number of events to return, must be an integer greater than 0.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

not_senders [string]

A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter.

not_types [string]

A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A ‘*’ can be used as a wildcard to match any sequence of characters.

senders [string]

A list of senders IDs to include. If this list is absent then all senders are included.

types [string]

A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.

RoomFilter
Name Type Description
account_data RoomEventFilter

The per user account data to include for rooms.

ephemeral RoomEventFilter

The ephemeral events to include for rooms. These are the events that appear in the ephemeral property in the /sync response.

include_leave boolean

Include rooms that the user has left in the sync, default false

not_rooms [string]

A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter. This filter is applied before the filters in ephemeral, state, timeline or account_data

rooms [string]

A list of room IDs to include. If this list is absent then all rooms are included. This filter is applied before the filters in ephemeral, state, timeline or account_data

state RoomEventFilter

The state events to include for rooms.

timeline RoomEventFilter

The message and state update events to include for rooms.

RoomEventFilter
Name Type Description
contains_url boolean

If true, includes only events with a url key in their content. If false, excludes those events. If omitted, url key is not considered for filtering.

include_redundant_members boolean

If true, sends all membership events for all events, even if they have already been sent to the client. Does not apply unless lazy_load_members is true. See Lazy-loading room members for more information. Defaults to false.

lazy_load_members boolean

If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false.

limit integer

The maximum number of events to return, must be an integer greater than 0.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

not_rooms [string]

A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter.

not_senders [string]

A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter.

not_types [string]

A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A ‘*’ can be used as a wildcard to match any sequence of characters.

rooms [string]

A list of room IDs to include. If this list is absent then all rooms are included.

senders [string]

A list of senders IDs to include. If this list is absent then all senders are included.

types [string]

A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.

unread_thread_notifications boolean

If true, enables per-thread notification counts. Only applies to the /sync endpoint. Defaults to false.

Added in v1.4

Request body example

{
  "event_fields": [
    "type",
    "content",
    "sender"
  ],
  "event_format": "client",
  "presence": {
    "not_senders": [
      "@alice:example.com"
    ],
    "types": [
      "m.presence"
    ]
  },
  "room": {
    "ephemeral": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.receipt",
        "m.typing"
      ]
    },
    "state": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "types": [
        "m.room.*"
      ]
    },
    "timeline": {
      "limit": 10,
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.room.message"
      ]
    }
  }
}

Responses

Status Description
200 The filter was created.

200 response

Name Type Description
filter_id string

Required: The ID of the filter that was created. Cannot start with a { as this character is used to determine if the filter provided is inline JSON or a previously declared filter by homeservers on some APIs.

{
  "filter_id": "66696p746572"
}

GET /_matrix/client/v3/user/{userId}/filter/{filterId}


Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
filterId string

Required: The filter ID to download.

userId string

Required: The user ID to download a filter for.


Responses

Status Description
200 The filter definition.
404 Unknown filter.

200 response

Filter
Name Type Description
account_data EventFilter

The user account data that isn’t associated with rooms to include.

event_fields [string]

List of event fields to include. If this list is absent then all fields are included. The entries are dot-separated paths for each property to include. So [‘content.body’] will include the ‘body’ field of the ‘content’ object. A server may include more fields than were requested.

event_format string

The format to use for events. ‘client’ will return the events in a format suitable for clients. ‘federation’ will return the raw event as received over federation. The default is ‘client’.

One of: [client, federation].

presence EventFilter

The presence updates to include.

room RoomFilter

Filters to be applied to room data.

EventFilter
Name Type Description
limit integer

The maximum number of events to return, must be an integer greater than 0.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

not_senders [string]

A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter.

not_types [string]

A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A ‘*’ can be used as a wildcard to match any sequence of characters.

senders [string]

A list of senders IDs to include. If this list is absent then all senders are included.

types [string]

A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.

RoomFilter
Name Type Description
account_data RoomEventFilter

The per user account data to include for rooms.

ephemeral RoomEventFilter

The ephemeral events to include for rooms. These are the events that appear in the ephemeral property in the /sync response.

include_leave boolean

Include rooms that the user has left in the sync, default false

not_rooms [string]

A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter. This filter is applied before the filters in ephemeral, state, timeline or account_data

rooms [string]

A list of room IDs to include. If this list is absent then all rooms are included. This filter is applied before the filters in ephemeral, state, timeline or account_data

state RoomEventFilter

The state events to include for rooms.

timeline RoomEventFilter

The message and state update events to include for rooms.

RoomEventFilter
Name Type Description
contains_url boolean

If true, includes only events with a url key in their content. If false, excludes those events. If omitted, url key is not considered for filtering.

include_redundant_members boolean

If true, sends all membership events for all events, even if they have already been sent to the client. Does not apply unless lazy_load_members is true. See Lazy-loading room members for more information. Defaults to false.

lazy_load_members boolean

If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false.

limit integer

The maximum number of events to return, must be an integer greater than 0.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

not_rooms [string]

A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter.

not_senders [string]

A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter.

not_types [string]

A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A ‘*’ can be used as a wildcard to match any sequence of characters.

rooms [string]

A list of room IDs to include. If this list is absent then all rooms are included.

senders [string]

A list of senders IDs to include. If this list is absent then all senders are included.

types [string]

A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.

unread_thread_notifications boolean

If true, enables per-thread notification counts. Only applies to the /sync endpoint. Defaults to false.

Added in v1.4

{
  "event_fields": [
    "type",
    "content",
    "sender"
  ],
  "event_format": "client",
  "presence": {
    "not_senders": [
      "@alice:example.com"
    ],
    "types": [
      "m.presence"
    ]
  },
  "room": {
    "ephemeral": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.receipt",
        "m.typing"
      ]
    },
    "state": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "types": [
        "m.room.*"
      ]
    },
    "timeline": {
      "limit": 10,
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.room.message"
      ]
    }
  }
}

事件

客户端-服务器 API 披露的会话历史为事件列表。服务器将最终一致的事件图(event graph)线性化为事件流(event stream):

[E0]->[E1]->[E2]->[E3]->[E4]->[E5]

房间事件类型

房间事件分为两类:

  • 状态事件:更新房间元数据(如话题、成员等),状态由事件 typestate_key 组成唯一键,重复键的状态会被覆盖。
  • 消息事件:描述房间内临时性操作,如发送消息、设置 VoIP 通话等。

规范定义了若干 m. 前缀事件(详见 Room Events)。应用可自定义事件类型,建议采用 Java 包命名规范如 com.example.myapp.event

事件类型不限于本规范定义,可随意采用 Java 包命名进行自定义,只要客户端可访问所用命名空间。例如 com.example.game.score

房间事件格式

“联邦”层事件格式依房间使用的房间版本而定,详见 版本1版本3

但一般客户端不会直接遇到此格式,主服务器会将事件转换为如下便于客户端解析的格式。

事件体属于不可信数据。所有 Matrix 应用须确保事件体结构/架构符合预期后再用其内容。

任何时候都不能假定事件体字段齐全且类型正确。

原因详见 MSC2801

ClientEvent


The format used for events when they are returned from a homeserver to a client via the Client-Server API, or sent to an Application Service via the Application Services API.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

Examples

{
  "content": {
    "membership": "join"
  },
  "event_id": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
  "origin_server_ts": 1632489532305,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@user:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1567437,
    "membership": "join",
    "redacted_because": {
      "content": {
        "reason": "spam"
      },
      "event_id": "$Nhl3rsgHMjk-DjMJANawr9HHAhLg4GcoTYrSiYYGqEE",
      "origin_server_ts": 1632491098485,
      "redacts": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
      "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
      "sender": "@moderator:example.org",
      "type": "m.room.redaction",
      "unsigned": {
        "age": 1257,
        "membership": "leave"
      }
    }
  }
}

精简(Stripped)状态

精简状态为房间的简化状态视图,助用户了解房间基本信息,仅含部分精简后的状态事件。

精简状态事件仅有 sendertypestate_keycontent

使用场景:邀请、敲门及用户可能有加入权利的房间(如 restricted 房间)。

客户端仅于无房间实际状态时应使用精简状态,有数据后弃用。如客户端带房间存档而收到房间精简状态(如被踢后看到新邀请),应以精简状态为准,直到重新进房获取最新状态。

精简状态一般包含下列事件,尽量以精简状态形式呈现:

客户端应遍历精简状态,不要假设某事件必然存在。服务器亦可包含文档未列出的事件。

房间名、头像、话题、别名便于用户做出加入与否。 加入规则提醒客户端为何具备加入权限,比如不同图标辅助解释。 创建事件可判定房间类型(如是否为空间等),客户端可据此在 UI 不同区域展示。 加密信息则用于图标或相关解释。

尽管精简状态由服务器生成与下发,但接收方亦可能不准确。精简状态事件未签名,有被篡改或因延迟变更未达等可能。

Stripped state event


A stripped down state event, with only the type, state_key, sender, and content keys.

Name Type Description
content EventContent

Required: The content for the event.

sender string

Required: The sender for the event.

state_key string

Required: The state_key for the event.

type string

Required: The type for the event.

大小限制

事件经联邦层格式规范化 JSON 编码后,整体不得超过 65536 字节。

字段单独限制如下:

  • sender 不得超过用户 ID 最大长度。
  • room_id 不得超过房间ID最大长度。
  • state_key 最多255字节。
  • type 最多255字节。
  • event_id 不得超过事件ID最大长度。

部分事件类型还有其他约束,详见各事件说明。其余键仅受全局 64KiB 限制。

房间事件

本节内容尚在完善中。

规范现有标准事件均以 m. 开头。

m.room.canonical_alias


This event is used to inform the room about which alias should be considered the canonical one, and which other aliases point to the room. This could be for display purposes or as suggestion to users which alias to use to advertise and access the room.

Event type: State event
State key A zero-length string.

Content

Name Type Description
alias string

The canonical alias for the room. If not present, null, or empty the room should be considered to have no canonical alias.

alt_aliases [string]

Alternative aliases the room advertises. This list can have aliases despite the alias field being null, empty, or otherwise not present.

Examples

{
  "content": {
    "alias": "#somewhere:localhost",
    "alt_aliases": [
      "#somewhere:example.org",
      "#myroom:example.com"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.canonical_alias",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.create


This is the first event in a room and cannot be changed. It acts as the root of all other events.

Event type: State event
State key A zero-length string.

Content

Name Type Description
creator string

The user_id of the room creator. Required for, and only present in, room versions 1 - 10. Starting with room version 11 the event sender should be used instead.

m.federate boolean

Whether users on other servers can join this room. Defaults to true if key does not exist.

predecessor Previous Room

A reference to the room this room replaces, if the previous room was upgraded.

room_version string

The version of the room. Defaults to "1" if the key does not exist.

type string

Optional room type to denote a room’s intended function outside of traditional conversation.

Unspecified room types are possible using Namespaced Identifiers.

Previous Room
Name Type Description
event_id string

Required: The event ID of the last known event in the old room.

room_id string

Required: The ID of the old room.

Examples

{
  "content": {
    "m.federate": true,
    "predecessor": {
      "event_id": "$something:example.org",
      "room_id": "!oldroom:example.org"
    },
    "room_version": "11"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.create",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.join_rules


A room may have one of the following designations:

  • public - anyone can join the room without any prior action.
  • invite - a user must first receive an invite from someone already in the room in order to join.
  • knock - a user can request an invite to the room. They can be allowed (invited) or denied (kicked/banned) access. Otherwise, users need to be invited in. Only available in rooms which support knocking.
  • 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.
  • 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.
  • private - reserved without implementation. No significant meaning.
Event type: State event
State key A zero-length string.

Content

Name Type Description
allow [AllowCondition]

For restricted rooms, the conditions the user will be tested against. The user needs only to satisfy one of the conditions to join the restricted room. If the user fails to meet any condition, or the condition is unable to be confirmed as satisfied, then the user requires an invite to join the room. Improper or no allow conditions on a restricted join rule imply the room is effectively invite-only (no conditions can be satisfied).

Added in v1.2

join_rule string

Required: The type of rules used for users wishing to join this room.

One of: [public, knock, invite, private, restricted, knock_restricted].

AllowCondition
Name Type Description
room_id string

Required if type is m.room_membership. The room ID to check the user’s membership against. If the user is joined to this room, they satisfy the condition and thus are permitted to join the restricted room.

type string

Required: The type of condition:

  • m.room_membership - the user satisfies the condition if they are joined to the referenced room.

One of: [m.room_membership].

Examples

{
  "content": {
    "join_rule": "public"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.join_rules",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}
{
  "content": {
    "allow": [
      {
        "room_id": "!other:example.org",
        "type": "m.room_membership"
      },
      {
        "room_id": "!elsewhere:example.org",
        "type": "m.room_membership"
      }
    ],
    "join_rule": "restricted"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.join_rules",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.member


Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (/rooms/<room id>/invite etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying to force this state change directly will fail.

The following membership states are specified:

  • invite - The user has been invited to join a room, but has not yet joined it. They may not participate in the room until they join.
  • join - The user has joined the room (possibly after accepting an invite), and may participate in it.
  • leave - The user was once joined to the room, but has since left (possibly by choice, or possibly by being kicked).
  • ban - The user has been banned from the room, and is no longer allowed to join it until they are un-banned from the room (by having their membership state set to a value other than ban).
  • knock - The user has knocked on the room, requesting permission to participate. They may not participate in the room until they join.

The third_party_invite property will be set if this invite is an invite event and is the successor of an m.room.third_party_invite event, and absent otherwise.

This event may also include an invite_room_state key inside the event’s unsigned data. If present, this contains an array of stripped state events to assist the receiver in identifying the room.

The user for which a membership applies is represented by the state_key. Under some conditions, the sender and state_key may not match - this may be interpreted as the sender affecting the membership state of the state_key user.

The membership for a given user can change over time. The table below represents the various changes over time and how clients and servers must interpret those changes. Previous membership can be retrieved from the prev_content object on an event. If not present, the user’s previous membership must be assumed as leave.

to invite to join to leave to ban to knock
from invite No change. User joined the room. If the state_key is the same as the sender, the user rejected the invite. Otherwise, the state_key user had their invite revoked. User was banned. User is re-knocking.
from join Must never happen. displayname or avatar_url changed. If the state_key is the same as the sender, the user left. Otherwise, the state_key user was kicked. User was kicked and banned. Must never happen.
from leave New invitation sent. User joined. No change. User was banned. User is knocking.
from ban Must never happen. Must never happen. User was unbanned. No change. Must never happen.
from knock Knock accepted. Must never happen. If the state_key is the same as the sender, the user retracted the knock. Otherwise, the state_key user had their knock denied. User was banned. No change.
Event type: State event
State key The user_id this membership event relates to. In all cases except for when membership is join, the user ID sending the event does not need to match the user ID in the state_key, unlike other events. Regular authorisation rules still apply.

Content

EventContent
Name Type Description
avatar_url URI

The avatar URL for this user, if any.

displayname string|null

The display name for this user, if any.

is_direct boolean

Flag indicating if the room containing this event was created with the intention of being a direct chat. See Direct Messaging.

join_authorised_via_users_server string

Usually found on join events, this field is used to denote which homeserver (through representation of a user with sufficient power level) authorised the user’s join. More information about this field can be found in the Restricted Rooms Specification.

Client and server implementations should be aware of the signing implications of including this field in further events: in particular, the event must be signed by the server which owns the user ID in the field. When copying the membership event’s content (for profile updates and similar) it is therefore encouraged to exclude this field in the copy, as otherwise the event might fail event authorization.

Added in v1.2

membership string

Required: The membership state of the user.

One of: [invite, join, knock, leave, ban].

reason string

Optional user-supplied text for why their membership has changed. For kicks and bans, this is typically the reason for the kick or ban. For other membership changes, this is a way for the user to communicate their intent without having to send a message to the room, such as in a case where Bob rejects an invite from Alice about an upcoming concert, but can’t make it that day.

Clients are not recommended to show this reason to users when receiving an invite due to the potential for spam and abuse. Hiding the reason behind a button or other component is recommended.

Added in v1.1

third_party_invite Invite
Invite
Name Type Description
display_name string

Required: A name which can be displayed to represent the user instead of their third-party identifier

signed signed

Required: A block of content which has been signed, which servers can use to verify the event. Clients should ignore this.

signed
Name Type Description
mxid string

Required: The invited matrix user ID. Must be equal to the user_id property of the event.

signatures {string: {string: string}}

Required: A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API.

token string

Required: The token property of the containing third_party_invite object.

Examples

{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "join",
    "reason": "Looking for support"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "invite",
    "reason": "Looking for support"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234,
    "invite_room_state": [
      {
        "content": {
          "name": "Example Room"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.name"
      },
      {
        "content": {
          "join_rule": "invite"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.join_rules"
      }
    ]
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "join_authorised_via_users_server": "@bob:other.example.org",
    "membership": "join"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "knock",
    "reason": "Looking for support"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234,
    "knock_room_state": [
      {
        "content": {
          "name": "Example Room"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.name"
      },
      {
        "content": {
          "join_rule": "knock"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.join_rules"
      }
    ]
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "invite",
    "third_party_invite": {
      "display_name": "alice",
      "signed": {
        "mxid": "@alice:example.org",
        "signatures": {
          "magic.forest": {
            "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
          }
        },
        "token": "abc123"
      }
    }
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.power_levels


This event specifies the minimum level a user must have in order to perform a certain action. It also specifies the levels of each user in the room.

If a user_id is in the users list, then that user_id has the associated power level. Otherwise they have the default level users_default. If users_default is not supplied, it is assumed to be 0. If the room contains no m.room.power_levels event, the room’s creator has a power level of 100, and all other users have a power level of 0.

The level required to send a certain event is governed by events, state_default and events_default. If an event type is specified in events, then the user must have at least the level specified in order to send that event. If the event type is not supplied, it defaults to events_default for Message Events and state_default for State Events.

If there is no state_default in the m.room.power_levels event, or there is no m.room.power_levels event, the state_default is 50. If there is no events_default in the m.room.power_levels event, or there is no m.room.power_levels event, the events_default is 0.

The power level required to invite a user to the room, kick a user from the room, ban a user from the room, or redact an event sent by another user, is defined by invite, kick, ban, and redact, respectively. The levels for kick, ban and redact default to 50 if they are not specified in the m.room.power_levels event, or if the room contains no m.room.power_levels event. invite defaults to 0 in either case.

Note:

The allowed range for power level values is [-(2**53)+1, (2**53)-1], as required by the Canonical JSON specification.

Event type: State event
State key A zero-length string.

Content

Name Type Description
ban integer

The level required to ban a user. Defaults to 50 if unspecified.

events {string: integer}

The level required to send specific event types. This is a mapping from event type to power level required.

events_default integer

The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.

invite integer

The level required to invite a user. Defaults to 0 if unspecified.

kick integer

The level required to kick a user. Defaults to 50 if unspecified.

notifications Notifications

The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.

redact integer

The level required to redact an event sent by another user. Defaults to 50 if unspecified.

state_default integer

The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.

users {User ID: integer}

The power levels for specific users. This is a mapping from user_id to power level for that user.

users_default integer

The power level for users in the room whose user_id is not mentioned in the users key. Defaults to 0 if unspecified.

Note: When there is no m.room.power_levels event in the room, the room creator has a power level of 100, and all other users have a power level of 0.

Notifications
Name Type Description
room integer

The level required to trigger an @room notification. Defaults to 50 if unspecified.

<Other properties> integer

Examples

{
  "content": {
    "ban": 50,
    "events": {
      "m.room.name": 100,
      "m.room.power_levels": 100
    },
    "events_default": 0,
    "invite": 50,
    "kick": 50,
    "notifications": {
      "room": 20
    },
    "redact": 50,
    "state_default": 50,
    "users": {
      "@example:localhost": 100
    },
    "users_default": 0
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.power_levels",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

历史性事件

部分 m. 命名空间下的事件或见于房间,但本规范暂无业务含义,如:

  • m.room.aliases

早期版本有详细定义。

同步

读取事件的推荐流程为:客户端首次调用 /sync(无 since 参数),获取每间房最新消息及房间在返回时间线开头时的状态。响应含 next_batch 字段,后续以此为 since 参数获取新消息。每房间附带 prev_batch 字段,可用作 /rooms/<room_id>/messages 的 start 参数查询更早记录。

举例,/sync 返回房间事件 E2~E5,略去 E0/E1:

    [E0]->[E1]->[E2]->[E3]->[E4]->[E5]
               ^                      ^
               |                      |
         prev_batch: '1-2-3'        next_batch: 'a-b-c'

客户端后续带 next_batchtimeout 长轮询。服务器会保持连接,及时有新事件随时返回,仅 /sync(及已弃用的 /events)支持该机制。

假如下一次同步返回增量事件 E6:

    [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]
                                      ^     ^
                                      |     |
                                      |  next_batch: 'x-y-z'
                                    prev_batch: 'a-b-c'

通常全部新事件都会返回。若某段时间事件过多,则大部分事件会省略,仅返回最新事件,同时返回起止区间状态差量(delta),方便客户端补全,防断层。客户端如想回补,可按返回 prev_batch 查询丢失区间事件。

例,跟进一次 /syncsince=x-y-z,服务器发现新事件 E7E10,但只返回 E8E10 及前置状态差量:

                                            | gap |
                                            | <-> |
    [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
                                            ^     ^                  ^
                                            |     |                  |
                                 since: 'x-y-z'   |                  |
                                       prev_batch: 'd-e-f'       next_batch: 'u-v-w'

客户端据此以 from=x-y-zto=d-e-f 查询 /rooms/<room_id>/messages 补历史。

此 API 按事件到达主服务器时间排序,部分旧 API 按事件图偏序排序,二者可能出现同事件多次返回。客户端需基于事件 ID 去重。

/sync 返回 state 列表与 timeline 分离。全量同步 state 为时间线开始时刻完整状态(如新房间状态只占满时间线 state 或为零)。增量同步 state 为自 since 以来至时间线起点的变更(如时间线 limited 时)。注意 state 不一定为时间线前一刻状态,客户端不应对时间线混排该列表。

本规范早期让 state 表示时间线末端状态,不理想:一是事件重复,二是客户端难以还原。例如返回时间线 [M0, S1, M2],M0/M2 同一用户发,S1 为其改昵称事件;若 state 表示末端,客户端需手动倒回 S1 状态计算 M0。

GET /_matrix/client/v3/sync


Synchronise the client’s state with the latest state on the server. Clients use this API when they first log in to get an initial snapshot of the state on the server, and then continue to call this API to get incremental deltas to the state, and to receive new messages.

Note: This endpoint supports lazy-loading. See Filtering for more information. Lazy-loading members is only supported on the state part of a RoomFilter for this endpoint. When lazy-loading is enabled, servers MUST include the syncing user’s own membership event when they join a room, or when the full state of rooms is requested, to aid discovering the user’s avatar & displayname.

Further, like other members, the user’s own membership event is eligible for being considered redundant by the server. When a sync is limited, the server MUST return membership events for events in the gap (between since and the start of the returned timeline), regardless as to whether or not they are redundant. This ensures that joins/leaves and profile changes which occur during the gap are not lost.

Note that the default behaviour of state is to include all membership events, alongside other state, when lazy-loading is not enabled.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
filter string

The ID of a filter created using the filter API or a filter JSON object encoded as a string. The server will detect whether it is an ID or a JSON object by whether the first character is a "{" open brace. Passing the JSON inline is best suited to one off requests. Creating a filter using the filter API is recommended for clients that reuse the same filter multiple times, for example in long poll requests.

See Filtering for more information.

full_state boolean

Controls whether to include the full state for all rooms the user is a member of.

If this is set to true, then all state events will be returned, even if since is non-empty. The timeline will still be limited by the since parameter. In this case, the timeout parameter will be ignored and the query will return immediately, possibly with an empty timeline.

If false, and since is non-empty, only state which has changed since the point indicated by since will be returned.

By default, this is false.

set_presence string

Controls whether the client is automatically marked as online by polling this API. If this parameter is omitted then the client is automatically marked as online when it uses this API. Otherwise if the parameter is set to “offline” then the client is not marked as being online when it uses this API. When set to “unavailable”, the client is marked as being idle.

One of: [offline, online, unavailable].

since string

A point in time to continue a sync from. This should be the next_batch token returned by an earlier call to this endpoint.

timeout integer

The maximum time to wait, in milliseconds, before returning this request. If no events (or other data) become available before this time elapses, the server will return a response with empty fields.

By default, this is 0, so the server will return immediately even if the response is empty.


Responses

Status Description
200 The initial snapshot or delta for the client to use to update their state.

200 response

Name Type Description
account_data Account Data

The global private data created by this user.

device_lists DeviceLists

Information on end-to-end device updates, as specified in End-to-end encryption.

device_one_time_keys_count {string: integer}

Information on end-to-end encryption keys, as specified in End-to-end encryption.

next_batch string

Required: The batch token to supply in the since param of the next /sync request.

presence Presence

The updates to the presence status of other users.

rooms Rooms

Updates to rooms.

to_device ToDevice

Information on the send-to-device messages for the client device, as defined in Send-to-Device messaging.

Account Data
Name Type Description
events [Event]

List of events.

Event
Name Type Description
content object

Required: The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.

type string

Required: The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. ‘com.example.subdomain.event.type’

Presence
Name Type Description
events [Event]

List of events.

Rooms
Name Type Description
invite {Room ID: Invited Room}

The rooms that the user has been invited to, mapped as room ID to room information.

join {Room ID: Joined Room}

The rooms that the user has joined, mapped as room ID to room information.

knock {Room ID: Knocked Room}

The rooms that the user has knocked upon, mapped as room ID to room information.

leave {Room ID: Left Room}

The rooms that the user has left or been banned from, mapped as room ID to room information.

Invited Room
Name Type Description
invite_state InviteState

The stripped state of a room that the user has been invited to.

InviteState
Name Type Description
events [StrippedStateEvent]

The stripped state events that form the invite state.

StrippedStateEvent
Name Type Description
content EventContent

Required: The content for the event.

sender string

Required: The sender for the event.

state_key string

Required: The state_key for the event.

type string

Required: The type for the event.

Joined Room
Name Type Description
account_data Account Data

The private data that this user has attached to this room.

ephemeral Ephemeral

The new ephemeral events in the room (events that aren’t recorded in the timeline or state of the room). In this version of the spec, these are typing notification and read receipt events.

state State

Updates to the state, between the time indicated by the since parameter, and the start of the timeline (or all state up to the start of the timeline, if since is not given, or full_state is true).

N.B. state updates for m.room.member events will be incomplete if lazy_load_members is enabled in the /sync filter, and only return the member events required to display the senders of the timeline events in this response.

summary RoomSummary

Information about the room which clients may need to correctly render it to users.

timeline Timeline

The timeline of messages and state changes in the room.

unread_notifications Unread Notification Counts

Counts of unread notifications for this room. See the Receiving notifications section for more information on how these are calculated.

If unread_thread_notifications was specified as true on the RoomEventFilter, these counts will only be for the main timeline rather than all events in the room. See the threading module for more information.

Changed in v1.4: Updated to reflect behaviour of having unread_thread_notifications as true in the RoomEventFilter for /sync.

unread_thread_notifications {Event ID: ThreadNotificationCounts}

If unread_thread_notifications was specified as true on the RoomEventFilter, the notification counts for each thread in this room. The object is keyed by thread root ID, with values matching unread_notifications.

If a thread does not have any notifications it can be omitted from this object. If no threads have notification counts, this whole object can be omitted.

Added in v1.4

Ephemeral
Name Type Description
events [Event]

List of events.

State
Name Type Description
events [ClientEventWithoutRoomID]

List of events.

ClientEventWithoutRoomID
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEventWithoutRoomID

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

RoomSummary
Name Type Description
m.heroes [string]

The users which can be used to generate a room name if the room does not have one. Required if the room’s m.room.name or m.room.canonical_alias state events are unset or empty.

This should be the first 5 members of the room, ordered by stream ordering, which are joined or invited. The list must never include the client’s own user ID. When no joined or invited members are available, this should consist of the banned and left users. More than 5 members may be provided, however less than 5 should only be provided when there are less than 5 members to represent.

When lazy-loading room members is enabled, the membership events for the heroes MUST be included in the state, unless they are redundant. When the list of users changes, the server notifies the client by sending a fresh list of heroes. If there are no changes since the last sync, this field may be omitted.

m.invited_member_count integer

The number of users with membership of invite. If this field has not changed since the last sync, it may be omitted. Required otherwise.

m.joined_member_count integer

The number of users with membership of join, including the client’s own user ID. If this field has not changed since the last sync, it may be omitted. Required otherwise.

Timeline
Name Type Description
events [ClientEventWithoutRoomID]

Required: List of events.

limited boolean

True if the number of events returned was limited by the limit on the filter.

prev_batch string

A token that can be supplied to the from parameter of the /rooms/<room_id>/messages endpoint in order to retrieve earlier events. If no earlier events are available, this property may be omitted from the response.

Unread Notification Counts
Name Type Description
highlight_count integer

The number of unread notifications for this room with the highlight flag set.

notification_count integer

The total number of unread notifications for this room.

ThreadNotificationCounts
Name Type Description
highlight_count integer

The number of unread notifications for this thread with the highlight flag set.

notification_count integer

The total number of unread notifications for this thread.

Knocked Room
Name Type Description
knock_state KnockState

The stripped state of a room that the user has knocked upon.

KnockState
Name Type Description
events [StrippedStateEvent]

The stripped state events that form the knock state.

Left Room
Name Type Description
account_data Account Data

The private data that this user has attached to this room.

state State

The state updates for the room up to the start of the timeline.

timeline Timeline

The timeline of messages and state changes in the room up to the point when the user left.

{
  "account_data": {
    "events": [
      {
        "content": {
          "custom_config_key": "custom_config_value"
        },
        "type": "org.example.custom.config"
      }
    ]
  },
  "next_batch": "s72595_4483_1934",
  "presence": {
    "events": [
      {
        "content": {
          "avatar_url": "mxc://localhost/wefuiwegh8742w",
          "currently_active": false,
          "last_active_ago": 2478593,
          "presence": "online",
          "status_msg": "Making cupcakes"
        },
        "sender": "@example:localhost",
        "type": "m.presence"
      }
    ]
  },
  "rooms": {
    "invite": {
      "!696r7674:example.com": {
        "invite_state": {
          "events": [
            {
              "content": {
                "name": "My Room Name"
              },
              "sender": "@alice:example.com",
              "state_key": "",
              "type": "m.room.name"
            },
            {
              "content": {
                "membership": "invite"
              },
              "sender": "@alice:example.com",
              "state_key": "@bob:example.com",
              "type": "m.room.member"
            }
          ]
        }
      }
    },
    "join": {
      "!726s6s6q:example.com": {
        "account_data": {
          "events": [
            {
              "content": {
                "tags": {
                  "u.work": {
                    "order": 0.9
                  }
                }
              },
              "type": "m.tag"
            },
            {
              "content": {
                "custom_config_key": "custom_config_value"
              },
              "type": "org.example.custom.room.config"
            }
          ]
        },
        "ephemeral": {
          "events": [
            {
              "content": {
                "user_ids": [
                  "@alice:matrix.org",
                  "@bob:example.com"
                ]
              },
              "type": "m.typing"
            },
            {
              "content": {
                "$1435641916114394fHBLK:matrix.org": {
                  "m.read": {
                    "@erikj:jki.re": {
                      "ts": 1436451550453
                    }
                  },
                  "m.read.private": {
                    "@self:example.org": {
                      "ts": 1661384801651
                    }
                  }
                }
              },
              "type": "m.receipt"
            }
          ]
        },
        "state": {
          "events": [
            {
              "content": {
                "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
                "displayname": "Alice Margatroid",
                "membership": "join",
                "reason": "Looking for support"
              },
              "event_id": "$143273582443PhrSn:example.org",
              "origin_server_ts": 1432735824653,
              "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
              "sender": "@example:example.org",
              "state_key": "@alice:example.org",
              "type": "m.room.member",
              "unsigned": {
                "age": 1234,
                "membership": "join"
              }
            }
          ]
        },
        "summary": {
          "m.heroes": [
            "@alice:example.com",
            "@bob:example.com"
          ],
          "m.invited_member_count": 0,
          "m.joined_member_count": 2
        },
        "timeline": {
          "events": [
            {
              "content": {
                "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
                "displayname": "Alice Margatroid",
                "membership": "join",
                "reason": "Looking for support"
              },
              "event_id": "$143273582443PhrSn:example.org",
              "origin_server_ts": 1432735824653,
              "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
              "sender": "@example:example.org",
              "state_key": "@alice:example.org",
              "type": "m.room.member",
              "unsigned": {
                "age": 1234,
                "membership": "join"
              }
            },
            {
              "content": {
                "body": "This is an example text message",
                "format": "org.matrix.custom.html",
                "formatted_body": "<b>This is an example text message</b>",
                "msgtype": "m.text"
              },
              "event_id": "$143273582443PhrSn:example.org",
              "origin_server_ts": 1432735824653,
              "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
              "sender": "@example:example.org",
              "type": "m.room.message",
              "unsigned": {
                "age": 1234,
                "membership": "join"
              }
            }
          ],
          "limited": true,
          "prev_batch": "t34-23535_0_0"
        },
        "unread_notifications": {
          "highlight_count": 1,
          "notification_count": 5
        },
        "unread_thread_notifications": {
          "$threadroot": {
            "highlight_count": 3,
            "notification_count": 6
          }
        }
      }
    },
    "knock": {
      "!223asd456:example.com": {
        "knock_state": {
          "events": [
            {
              "content": {
                "name": "My Room Name"
              },
              "sender": "@alice:example.com",
              "state_key": "",
              "type": "m.room.name"
            },
            {
              "content": {
                "membership": "knock"
              },
              "sender": "@bob:example.com",
              "state_key": "@bob:example.com",
              "type": "m.room.member"
            }
          ]
        }
      }
    },
    "leave": {}
  }
}

GET /_matrix/client/v3/events


This API is deprecated and will be removed from a future release.

This will listen for new events and return them to the caller. This will block until an event is received, or until the timeout is reached.

This endpoint was deprecated in r0 of this specification. Clients should instead call the /sync endpoint with a since parameter. See the migration guide.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
from string

The token to stream from. This token is either from a previous request to this API or from the initial sync API.

timeout integer

The maximum time in milliseconds to wait for an event.


Responses

Status Description
200 The events received, which may be none.
400 Bad pagination from parameter.

200 response

Name Type Description
chunk [ClientEvent]

An array of events.

end string

A token which correlates to the end of chunk. This token should be used in the next request to /events.

start string

A token which correlates to the start of chunk. This is usually the same token supplied to from=.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "body": "This is an example text message",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>This is an example text message</b>",
        "msgtype": "m.text"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "end": "s3457_9_0",
  "start": "s3456_9_0"
}

GET /_matrix/client/v3/events/{eventId}


This API is deprecated and will be removed from a future release.

Get a single event based on event_id. You must have permission to retrieve this event e.g. by being a member in the room for this event.

This endpoint was deprecated in r0 of this specification. Clients should instead call the /rooms/{roomId}/event/{eventId} API or the /rooms/{roomId}/context/{eventId API.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The event ID to get.


Responses

Status Description
200 The full event.
404 The event was not found or you do not have permission to read this event.

200 response

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "<b>This is an example text message</b>",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

GET /_matrix/client/v3/initialSync


This API is deprecated and will be removed from a future release.

This returns the full state for this user, with an optional limit on the number of messages per room to return.

This endpoint was deprecated in r0 of this specification. Clients should instead call the /sync endpoint with no since parameter. See the migration guide.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
archived boolean

Whether to include rooms that the user has left. If false then only rooms that the user has been invited to or has joined are included. If set to true then rooms that the user has left are included as well. By default this is false.

limit integer

The maximum number of messages to return for each room.


Responses

Status Description
200 The user’s current state.
404 There is no avatar URL for this user or this user does not exist.

200 response

Name Type Description
account_data [Event]

The global private data created by this user.

end string

Required: A token which correlates to the end of the timelines returned. This token should be used with the /events endpoint to listen for new events.

presence [Event]

Required: A list of presence events.

rooms [RoomInfo]

Required:

Event
Name Type Description
content object

Required: The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.

type string

Required: The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. ‘com.example.subdomain.event.type’

RoomInfo
Name Type Description
account_data [Event]

The private data that this user has attached to this room.

invite InviteEvent

The invite event if membership is invite

membership string

Required: The user’s membership state in this room.

One of: [invite, join, leave, ban].

messages PaginationChunk

The pagination chunk for this room.

room_id string

Required: The ID of this room.

state [ClientEvent]

If the user is a member of the room this will be the current state of the room as a list of events. If the user has left the room this will be the state of the room when they left it.

visibility string

Whether this room is visible to the /publicRooms API or not.

One of: [private, public].

InviteEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

PaginationChunk
Name Type Description
chunk [ClientEvent]

Required: If the user is a member of the room this will be a list of the most recent messages for this room. If the user has left the room this will be the messages that preceded them leaving. This array will consist of at most limit elements.

end string

Required: A token which correlates to the end of chunk. Can be passed to /rooms/<room_id>/messages to retrieve later events.

start string

A token which correlates to the start of chunk. Can be passed to /rooms/<room_id>/messages to retrieve earlier events.

If no earlier events are available, this property may be omitted from the response.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

{
  "account_data": [
    {
      "content": {
        "custom_config_key": "custom_config_value"
      },
      "type": "org.example.custom.config"
    }
  ],
  "end": "s3456_9_0",
  "presence": [
    {
      "content": {
        "avatar_url": "mxc://localhost/wefuiwegh8742w",
        "currently_active": false,
        "last_active_ago": 2478593,
        "presence": "online",
        "status_msg": "Making cupcakes"
      },
      "sender": "@example:localhost",
      "type": "m.presence"
    }
  ],
  "rooms": [
    {
      "account_data": [
        {
          "content": {
            "tags": {
              "work": {
                "order": 1
              }
            }
          },
          "type": "m.tag"
        },
        {
          "content": {
            "custom_config_key": "custom_config_value"
          },
          "type": "org.example.custom.room.config"
        }
      ],
      "membership": "join",
      "messages": {
        "chunk": [
          {
            "content": {
              "body": "This is an example text message",
              "format": "org.matrix.custom.html",
              "formatted_body": "<b>This is an example text message</b>",
              "msgtype": "m.text"
            },
            "event_id": "$143273582443PhrSn:example.org",
            "origin_server_ts": 1432735824653,
            "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
            "sender": "@example:example.org",
            "type": "m.room.message",
            "unsigned": {
              "age": 1234,
              "membership": "join"
            }
          },
          {
            "content": {
              "body": "Gangnam Style",
              "info": {
                "duration": 2140786,
                "h": 320,
                "mimetype": "video/mp4",
                "size": 1563685,
                "thumbnail_info": {
                  "h": 300,
                  "mimetype": "image/jpeg",
                  "size": 46144,
                  "w": 300
                },
                "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
                "w": 480
              },
              "msgtype": "m.video",
              "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442"
            },
            "event_id": "$143273582443PhrSn:example.org",
            "origin_server_ts": 1432735824653,
            "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
            "sender": "@example:example.org",
            "type": "m.room.message",
            "unsigned": {
              "age": 1234,
              "membership": "join"
            }
          }
        ],
        "end": "s3456_9_0",
        "start": "t44-3453_9_0"
      },
      "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
      "state": [
        {
          "content": {
            "join_rule": "public"
          },
          "event_id": "$143273582443PhrSn:example.org",
          "origin_server_ts": 1432735824653,
          "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
          "sender": "@example:example.org",
          "state_key": "",
          "type": "m.room.join_rules",
          "unsigned": {
            "age": 1234,
            "membership": "join"
          }
        },
        {
          "content": {
            "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
            "displayname": "Alice Margatroid",
            "membership": "join",
            "reason": "Looking for support"
          },
          "event_id": "$143273582443PhrSn:example.org",
          "origin_server_ts": 1432735824653,
          "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
          "sender": "@example:example.org",
          "state_key": "@alice:example.org",
          "type": "m.room.member",
          "unsigned": {
            "age": 1234,
            "membership": "join"
          }
        },
        {
          "content": {
            "m.federate": true,
            "predecessor": {
              "event_id": "$something:example.org",
              "room_id": "!oldroom:example.org"
            },
            "room_version": "11"
          },
          "event_id": "$143273582443PhrSn:example.org",
          "origin_server_ts": 1432735824653,
          "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
          "sender": "@example:example.org",
          "state_key": "",
          "type": "m.room.create",
          "unsigned": {
            "age": 1234,
            "membership": "join"
          }
        },
        {
          "content": {
            "ban": 50,
            "events": {
              "m.room.name": 100,
              "m.room.power_levels": 100
            },
            "events_default": 0,
            "invite": 50,
            "kick": 50,
            "notifications": {
              "room": 20
            },
            "redact": 50,
            "state_default": 50,
            "users": {
              "@example:localhost": 100
            },
            "users_default": 0
          },
          "event_id": "$143273582443PhrSn:example.org",
          "origin_server_ts": 1432735824653,
          "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
          "sender": "@example:example.org",
          "state_key": "",
          "type": "m.room.power_levels",
          "unsigned": {
            "age": 1234,
            "membership": "join"
          }
        }
      ],
      "visibility": "private"
    }
  ]
}

获取房间事件

房间事件读取相关 API 如下:

GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}


Get a single event based on roomId/eventId. You must have permission to retrieve this event e.g. by being a member in the room for this event.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The event ID to get.

roomId string

Required: The ID of the room the event is in.


Responses

Status Description
200 The full event.
404 The event was not found or you do not have permission to read this event.

200 response

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "<b>This is an example text message</b>",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!636q39766251:matrix.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Event not found."
}

GET /_matrix/client/v3/rooms/{roomId}/joined_members


This API returns a map of MXIDs to member info objects for members of the room. The current user must be in the room for it to work, unless it is an Application Service in which case any of the AS’s users must be in the room. This API is primarily for Application Services and should be faster to respond than /members as it can be implemented more efficiently on the server.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room to get the members of.


Responses

Status Description
200 A map of MXID to room member objects.
403 You aren’t a member of the room.

200 response

Name Type Description
joined {User ID: RoomMember}

A map from user ID to a RoomMember object.

RoomMember
Name Type Description
avatar_url URI

The avatar of the user this object is representing, as an mxc:// URI.

display_name string

The display name of the user this object is representing.

{
  "joined": {
    "@bar:example.com": {
      "avatar_url": "mxc://riot.ovh/printErCATzZijQsSDWorRaK",
      "display_name": "Bar"
    }
  }
}

GET /_matrix/client/v3/rooms/{roomId}/members


Get the list of members for this room.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room to get the member events for.

query parameters
Name Type Description
at string

The point in time (pagination token) to return members for in the room. This token can be obtained from a prev_batch token returned for each room by the sync API. Defaults to the current state of the room, as determined by the server.

membership string

The kind of membership to filter for. Defaults to no filtering if unspecified. When specified alongside not_membership, the two parameters create an ‘or’ condition: either the membership is the same as membership or is not the same as not_membership.

One of: [join, invite, knock, leave, ban].

not_membership string

The kind of membership to exclude from the results. Defaults to no filtering if unspecified.

One of: [join, invite, knock, leave, ban].


Responses

Status Description
200 A list of members of the room. If you are joined to the room then this will be the current members of the room. If you have left the room then this will be the members of the room when you left.
403 You aren’t a member of the room and weren’t previously a member of the room.

200 response

Name Type Description
chunk [ClientEvent]
ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
        "displayname": "Alice Margatroid",
        "membership": "join",
        "reason": "Looking for support"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "@alice:example.org",
      "type": "m.room.member",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ]
}

GET /_matrix/client/v3/rooms/{roomId}/state


Get the state events for the current state of a room.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room to look up the state for.


Responses

Status Description
200 The current state of the room
403 You aren’t a member of the room and weren’t previously a member of the room.

200 response

Array of ClientEvent.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

[
  {
    "content": {
      "join_rule": "public"
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "",
    "type": "m.room.join_rules",
    "unsigned": {
      "age": 1234,
      "membership": "join"
    }
  },
  {
    "content": {
      "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
      "displayname": "Alice Margatroid",
      "membership": "join",
      "reason": "Looking for support"
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "@alice:example.org",
    "type": "m.room.member",
    "unsigned": {
      "age": 1234,
      "membership": "join"
    }
  },
  {
    "content": {
      "m.federate": true,
      "predecessor": {
        "event_id": "$something:example.org",
        "room_id": "!oldroom:example.org"
      },
      "room_version": "11"
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "",
    "type": "m.room.create",
    "unsigned": {
      "age": 1234,
      "membership": "join"
    }
  },
  {
    "content": {
      "ban": 50,
      "events": {
        "m.room.name": 100,
        "m.room.power_levels": 100
      },
      "events_default": 0,
      "invite": 50,
      "kick": 50,
      "notifications": {
        "room": 20
      },
      "redact": 50,
      "state_default": 50,
      "users": {
        "@example:localhost": 100
      },
      "users_default": 0
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "",
    "type": "m.room.power_levels",
    "unsigned": {
      "age": 1234,
      "membership": "join"
    }
  }
]

GET /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}


Looks up the contents of a state event in a room. If the user is joined to the room then the state is taken from the current state of the room. If the user has left the room then the state is taken from the state of the room when they left.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventType string

Required: The type of state to look up.

roomId string

Required: The room to look up the state in.

stateKey string

Required: The key of the state to look up. Defaults to an empty string. When an empty string, the trailing slash on this endpoint is optional.


Responses

Status Description
200 The content of the state event.
403 You aren’t a member of the room and weren’t previously a member of the room.
404 The room has no state with the given type or key.

200 response

{
  "name": "Example room name"
}

GET /_matrix/client/v3/rooms/{roomId}/messages


This API returns a list of message and state events for a room. It uses pagination query parameters to paginate history in the room.

Note: This endpoint supports lazy-loading of room member events. See Lazy-loading room members for more information.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room to get events from.

query parameters
Name Type Description
dir string

Required: The direction to return events from. If this is set to f, events will be returned in chronological order starting at from. If it is set to b, events will be returned in reverse chronological order, again starting at from.

One of: [b, f].

filter string

A JSON RoomEventFilter to filter returned events with.

from string

The token to start returning events from. This token can be obtained from a prev_batch or next_batch token returned by the /sync endpoint, or from an end token returned by a previous request to this endpoint.

This endpoint can also accept a value returned as a start token by a previous request to this endpoint, though servers are not required to support this. Clients should not rely on the behaviour.

If it is not provided, the homeserver shall return a list of messages from the first or last (per the value of the dir parameter) visible event in the room history for the requesting user.

Changed in v1.3: Previously, this field was required and paginating from the first or last visible event in the room history wasn’t supported.

limit integer

The maximum number of events to return. Default: 10.

to string

The token to stop returning events at. This token can be obtained from a prev_batch or next_batch token returned by the /sync endpoint, or from an end token returned by a previous request to this endpoint.


Responses

Status Description
200 A list of messages with a new token to request more.
403 You aren’t a member of the room.

200 response

Name Type Description
chunk [ClientEvent]

Required: A list of room events. The order depends on the dir parameter. For dir=b events will be in reverse-chronological order, for dir=f in chronological order. (The exact definition of chronological is dependent on the server implementation.)

Note that an empty chunk does not necessarily imply that no more events are available. Clients should continue to paginate until no end property is returned.

end string

A token corresponding to the end of chunk. This token can be passed back to this endpoint to request further events.

If no further events are available (either because we have reached the start of the timeline, or because the user does not have permission to see any more events), this property is omitted from the response.

start string

Required: A token corresponding to the start of chunk. This will be the same as the value given in from.

state [ClientEvent]

A list of state events relevant to showing the chunk. For example, if lazy_load_members is enabled in the filter then this may contain the membership events for the senders of events in the chunk.

Unless include_redundant_members is true, the server may remove membership events which would have already been sent to the client in prior calls to this endpoint, assuming the membership of those members has not changed.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "body": "This is an example text message",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>This is an example text message</b>",
        "msgtype": "m.text"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    },
    {
      "content": {
        "name": "The room name"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "",
      "type": "m.room.name",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    },
    {
      "content": {
        "body": "Gangnam Style",
        "info": {
          "duration": 2140786,
          "h": 320,
          "mimetype": "video/mp4",
          "size": 1563685,
          "thumbnail_info": {
            "h": 300,
            "mimetype": "image/jpeg",
            "size": 46144,
            "w": 300
          },
          "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
          "w": 480
        },
        "msgtype": "m.video",
        "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "end": "t47409-4357353_219380_26003_2265",
  "start": "t47429-4392820_219380_26003_2265"
}

GET /_matrix/client/v1/rooms/{roomId}/timestamp_to_event


Added in v1.6

Get the ID of the event closest to the given timestamp, in the direction specified by the dir parameter.

If the server does not have all of the room history and does not have an event suitably close to the requested timestamp, it can use the corresponding federation endpoint to ask other servers for a suitable event.

After calling this endpoint, clients can call /rooms/{roomId}/context/{eventId} to obtain a pagination token to retrieve the events around the returned event.

The event returned by this endpoint could be an event that the client cannot render, and so may need to paginate in order to locate an event that it can display, which may end up being outside of the client’s suitable range. Clients can employ different strategies to display something reasonable to the user. For example, the client could try paginating in one direction for a while, while looking at the timestamps of the events that it is paginating through, and if it exceeds a certain difference from the target timestamp, it can try paginating in the opposite direction. The client could also simply paginate in one direction and inform the user that the closest event found in that direction is outside of the expected range.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to search

query parameters
Name Type Description
dir string

Required: The direction in which to search. f for forwards, b for backwards.

One of: [f, b].

ts integer

Required: The timestamp to search from, as given in milliseconds since the Unix epoch.


Responses

Status Description
200 An event was found matching the search parameters.
404 No event was found.
429 This request was rate-limited.

200 response

Name Type Description
event_id string

Required: The ID of the event found

origin_server_ts integer

Required: The event’s timestamp, in milliseconds since the Unix epoch. This makes it easy to do a quick comparison to see if the event_id fetched is too far out of range to be useful for your use case.

{
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unable to find event from 1432684800000 in forward direction"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/rooms/{roomId}/initialSync


Get a copy of the current state and the most recent messages in a room.

This endpoint should now exclusively be used for “peeking” into viewable rooms you’re not a member of (Room Previews). Using this endpoint for something other than peeking was deprecated in r0 of this specification. The relevant information for syncing is now returned by the /sync API. See the migration guide.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room to get the data.


Responses

Status Description
200 The current state of the room
403 You aren’t a member of the room and weren’t previously a member of the room.

200 response

RoomInfo
Name Type Description
account_data [Event]

The private data that this user has attached to this room.

membership string

The user’s membership state in this room.

One of: [invite, join, leave, ban].

messages PaginationChunk

The pagination chunk for this room.

room_id string

Required: The ID of this room.

state [ClientEvent]

If the user is a member of the room this will be the current state of the room as a list of events. If the user has left the room this will be the state of the room when they left it.

visibility string

Whether this room is visible to the /publicRooms API or not.

One of: [private, public].

Event
Name Type Description
content object

Required: The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.

type string

Required: The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. ‘com.example.subdomain.event.type’

PaginationChunk
Name Type Description
chunk [ClientEvent]

Required: If the user is a member of the room this will be a list of the most recent messages for this room. If the user has left the room this will be the messages that preceded them leaving. This array will consist of at most limit elements.

end string

Required: A token which correlates to the end of chunk. Can be passed to /rooms/<room_id>/messages to retrieve later events.

start string

A token which correlates to the start of chunk. Can be passed to /rooms/<room_id>/messages to retrieve earlier events.

If no earlier events are available, this property may be omitted from the response.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "account_data": [
    {
      "content": {
        "tags": {
          "work": {
            "order": "1"
          }
        }
      },
      "type": "m.tag"
    }
  ],
  "membership": "join",
  "messages": {
    "chunk": [
      {
        "content": {
          "body": "This is an example text message",
          "format": "org.matrix.custom.html",
          "formatted_body": "<b>This is an example text message</b>",
          "msgtype": "m.text"
        },
        "event_id": "$143273582443PhrSn:example.org",
        "origin_server_ts": 1432735824653,
        "room_id": "!636q39766251:example.com",
        "sender": "@example:example.org",
        "type": "m.room.message",
        "unsigned": {
          "age": 1234,
          "membership": "join"
        }
      },
      {
        "content": {
          "body": "something-important.doc",
          "filename": "something-important.doc",
          "info": {
            "mimetype": "application/msword",
            "size": 46144
          },
          "msgtype": "m.file",
          "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
        },
        "event_id": "$143273582443PhrSn:example.org",
        "origin_server_ts": 1432735824653,
        "room_id": "!636q39766251:example.com",
        "sender": "@example:example.org",
        "type": "m.room.message",
        "unsigned": {
          "age": 1234,
          "membership": "join"
        }
      }
    ],
    "end": "s3456_9_0",
    "start": "t44-3453_9_0"
  },
  "room_id": "!636q39766251:example.com",
  "state": [
    {
      "content": {
        "join_rule": "public"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "",
      "type": "m.room.join_rules",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    },
    {
      "content": {
        "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
        "displayname": "Alice Margatroid",
        "membership": "join",
        "reason": "Looking for support"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "@alice:example.org",
      "type": "m.room.member",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    },
    {
      "content": {
        "m.federate": true,
        "predecessor": {
          "event_id": "$something:example.org",
          "room_id": "!oldroom:example.org"
        },
        "room_version": "11"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "",
      "type": "m.room.create",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    },
    {
      "content": {
        "ban": 50,
        "events": {
          "m.room.name": 100,
          "m.room.power_levels": 100
        },
        "events_default": 0,
        "invite": 50,
        "kick": 50,
        "notifications": {
          "room": 20
        },
        "redact": 50,
        "state_default": 50,
        "users": {
          "@example:localhost": 100
        },
        "users_default": 0
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "",
      "type": "m.room.power_levels",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "visibility": "private"
}

向房间发送事件

[Added in v1.3]

如事件 关联 其它事件,服务器可能做后处理。关联类型(rel_type)决定了可用性(如用户对同一目标事件只能发送一次)。

PUT /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}


State events can be sent using this endpoint. These events will be overwritten if <room id>, <event type> and <state key> all match.

Requests to this endpoint cannot use transaction IDs like other PUT paths because they cannot be differentiated from the state_key. Furthermore, POST is unsupported on state paths.

The body of the request should be the content object of the event; the fields in this object will vary depending on the type of event. See Room Events for the m. event specification.

If the event type being sent is m.room.canonical_alias servers SHOULD ensure that any new aliases being listed in the event are valid per their grammar/syntax and that they point to the room ID where the state event is to be sent. Servers do not validate aliases which are being removed or are already present in the state event.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventType string

Required: The type of event to send.

roomId string

Required: The room to set the state in

stateKey string

Required: The state_key for the state to send. Defaults to the empty string. When an empty string, the trailing slash on this endpoint is optional.

Request body

Request body example

{
  "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF",
  "displayname": "Alice Margatroid",
  "membership": "join"
}

Responses

Status Description
200 An ID for the sent event.
400

The sender’s request is malformed.

Some example error codes include:

  • M_INVALID_PARAM: One or more aliases within the m.room.canonical_alias event have invalid syntax.

  • M_BAD_ALIAS: One or more aliases within the m.room.canonical_alias event do not point to the room ID for which the state event is to be sent to.

403 The sender doesn’t have permission to send the event into the room.

200 response

Name Type Description
event_id string

Required: A unique identifier for the event.

{
  "event_id": "$YUwRidLecu:example.com"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_BAD_ALIAS",
  "error": "The alias '#hello:example.org' does not point to this room."
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You do not have permission to send the event."
}

示例

合法写法:

PUT /rooms/!roomid:domain/state/m.example.event
{ "key" : "without a state key" }
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
{ "key" : "with 'foo' as the state key" }

非法请求:

POST /rooms/!roomid:domain/state/m.example.event/
{ "key" : "cannot use POST here" }
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
{ "key" : "txnIds are not supported" }

注意区分 state keytxnId

PUT /rooms/!roomid:domain/state/m.another.example.event/11
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }

可按用户 ID 作为 state_key 存储用户相关状态:

PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
{ "animal" : "cat", "reason": "fluffy" }

也可无 state_key

PUT /rooms/!roomid:domain/state/m.room.bgd.color
{ "color": "red", "hex": "#ff0000" }

PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}


This endpoint is used to send a message event to a room. Message events allow access to historical events and pagination, making them suited for “once-off” activity in a room.

The body of the request should be the content object of the event; the fields in this object will vary depending on the type of event. See Room Events for the m. event specification.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventType string

Required: The type of event to send.

roomId string

Required: The room to send the event to.

txnId string

Required: The transaction ID for this event. Clients should generate an ID unique across requests with the same access token; it will be used by the server to ensure idempotency of requests.

Request body

Request body example

{
  "body": "hello",
  "msgtype": "m.text"
}

Responses

Status Description
200 An ID for the sent event.
400

The request is invalid. A standard error response will be returned. As well as the normal common error codes, other reasons for rejection include:

200 response

Name Type Description
event_id string

Required: A unique identifier for the event.

{
  "event_id": "$YUwRidLecu:example.com"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "An unknown error occurred"
}

撤回(Reductions)

因事件可扩展,恶意用户/服务器或添违法内容。部分事件无法直接删除(如成员事件),因此采用撤回手段,将事件只保留协议必需字段。撤回后的事件在客户端/服务器侧皆只返回精简内容。客户端访问已被撤回事件可在 unsigned 红包 redacted_because 带原撤回事件。

具体算法见房间版本说明。事件撤回后不可恢复。远程主服务器撤回有效性判据同理。

客户端接收到 m.room.redaction 事件时,须同步调整被撤回事件内容。

撤回事件仍能影响房间状态。撤回后,状态事件表现为属性未指定(除撤回算法保护外)。如撤回的 join 事件,用户仍为已加入;如撤回话题,则话题移除而非回滚至先前。

事件

m.room.redaction


This event is created by the server to describe which event has been redacted, by whom, and optionally why. The event that has been redacted is specified in the redacts event level key. Redacting an event means that all keys not required by the protocol are stripped off, allowing messages to be hidden or allowing admins to remove offensive or illegal content.

Event type: Message event

Content

Name Type Description
reason string

The reason for the redaction, if any.

redacts string

The event ID that was redacted. Required for, and present starting in, room version 11.

Examples

{
  "content": {
    "reason": "Spamming",
    "redacts": "$fukweghifu23:localhost"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.redaction",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

PUT /_matrix/client/v3/rooms/{roomId}/redact/{eventId}/{txnId}


Strips all information out of an event which isn’t critical to the integrity of the server-side representation of the room.

This cannot be undone.

Any user with a power level greater than or equal to the m.room.redaction event power level may send redaction events in the room. If the user’s power level is also greater than or equal to the redact power level of the room, the user may redact events sent by other users.

Server administrators may redact events sent by users on their server.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The ID of the event to redact

roomId string

Required: The room from which to redact the event.

txnId string

Required: The transaction ID for this event. Clients should generate a unique ID; it will be used by the server to ensure idempotency of requests.

Request body

Name Type Description
reason string

The reason for the event being redacted.

Request body example

{
  "reason": "Indecent material"
}

Responses

Status Description
200 An ID for the redaction event.

200 response

Name Type Description
event_id string

A unique identifier for the event.

{
  "event_id": "$YUwQidLecu:example.com"
}

形成事件关系

[Changed in v1.3]

部分场景需将一个事件逻辑关联至另一个,如回复消息、编辑、提供上下文等。

关联为父子结构,任意事件可为父。父不显式列子关系,由子通过 contentm.relates_to(见下)描述。可相互嵌套形成树。

子事件可指向其他子事件,形成链甚至树型结构。

为便于服务器聚合查找,m.relates_to 必须出现在加密事件的明文部分,不能仅内嵌在密文负载中。

加密事件内 payloadm.relates_to 应被忽略,只以明文副本为准(包括无副本时)。以确保客户端与服务器关于关系的处理一致。

不规范、非法、跨房间等关联均忽略。客户端应平等显示无效也无关联事件,可加以错误提示。

m.relates_to 格式定义如下:

m.relates_to


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.

m.relates_to
Name Type Description
event_id string

Required: The event ID of the event that this event relates to.

rel_type string

Required: The namespaced relationship type. Values must use the 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 denotes that the event is part of a “thread” of messages and should be rendered as such.

Examples

{
  "m.relates_to": {
    "event_id": "$an_event",
    "rel_type": "org.example.relationship"
  }
}

关联类型

本规范描述如下关联类型:

子事件聚合

[Added in v1.3]

部分关系可由服务器按 rel_type 聚合,让客户端无需单独获取所有子事件。例如可统计有多少用户用某 reaction key。

聚合详情因关联类型而异。

下述端点提供聚合:

当前状态事件不支持聚合。欢迎补充相关 MSC 以提升支持。

客户端应本地追加聚合。例如收到新 reaction,更新计数。若事件本地未能找到或发生变化,需自行整合。

被撤回的父事件,其子事件(如 reaction)依然存在,但被撤回的子事件与父失去关联,需要解除聚合关系。客户端本地聚合同理。

建议客户端对聚合实现本地回显,如优化用户体验。但需注意不可二次聚合。建议为尚未获取事件 ID 的发出事件也能维护聚合信息,可用事务 ID 临时识别。

若历史可见性受限,部分事件不可见,聚合也缺失。关键信息(如投票)应充分考虑可见性。

服务器如有历史断层,聚合也会不准确。

关系 API

[Added in v1.3]

客户端可通过下述端点取父事件的子事件,如需递归聚合则需自行处理。

通过 event_typerel_type 过滤条件,服务器仅返回匹配的直接/间接关联事件,所有非匹配类型的间接关联将被排除,如想获取完整线程建议客户端本地遍历而不是用 rel_type。

由于回复未使用 rel_type,无法通过本 API 访问。

GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}


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.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The ID of the parent event whose child events are to be returned.

roomId string

Required: The ID of the room containing the parent event.

query parameters
Name Type Description
dir string

Optional (default b) direction to return events from. If this is set to f, events will be returned in chronological order starting at from. If it is set to b, events will be returned in reverse chronological order, again starting at from.

One of: [b, f].

Added in v1.4

from string

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 or prev_batch token from a previous call, or a returned start token from /messages, or a next_batch token from /sync.

limit integer

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.

recurse boolean

Whether to additionally include events which only relate indirectly to the given event, i.e. events related to the given event via two or more direct relationships.

If set to false, only events which have a direct relation with the given event will be included.

If set to true, events which have an indirect relation with the given event will be included additionally up to a certain depth level. Homeservers SHOULD traverse at least 3 levels of relationships. Implementations MAY perform more but MUST be careful to not infinitely recurse.

The default value is false.

Added in v1.10

to string

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.


Responses

Status Description
200 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.
404 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).

200 response

Name Type Description
chunk [ClientEvent]

Required: The child events of the requested event, ordered topologically most-recent first.

next_batch string

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 string

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.

recursion_depth integer

If the recurse parameter was supplied by the client, this response field is mandatory and gives the actual depth to which the server recursed. If the client did not specify the recurse parameter, this field must be absent.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "m.relates_to": {
          "event_id": "$asfDuShaf7Gafaw",
          "rel_type": "org.example.my_relation"
        }
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:matrix.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "next_batch": "page2_token",
  "prev_batch": "page1_token"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Event not found."
}

GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}/{relType}


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.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The ID of the parent event whose child events are to be returned.

relType string

Required: The relationship type to search for.

roomId string

Required: The ID of the room containing the parent event.

query parameters
Name Type Description
dir string

Optional (default b) direction to return events from. If this is set to f, events will be returned in chronological order starting at from. If it is set to b, events will be returned in reverse chronological order, again starting at from.

One of: [b, f].

Added in v1.4

from string

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 or prev_batch token from a previous call, or a returned start token from /messages, or a next_batch token from /sync.

limit integer

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.

recurse boolean

Whether to additionally include events which only relate indirectly to the given event, i.e. events related to the given event via two or more direct relationships.

If set to false, only events which have a direct relation with the given event will be included.

If set to true, events which have an indirect relation with the given event will be included additionally up to a certain depth level. Homeservers SHOULD traverse at least 3 levels of relationships. Implementations MAY perform more but MUST be careful to not infinitely recurse.

The default value is false.

Added in v1.10

to string

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.


Responses

Status Description
200 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.
404 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).

200 response

Name Type Description
chunk [ClientEvent]

Required: The child events of the requested event, ordered topologically most-recent first. The events returned will match the relType supplied in the URL.

next_batch string

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 string

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.

recursion_depth integer

If the recurse parameter was supplied by the client, this response field is mandatory and gives the actual depth to which the server recursed. If the client did not specify the recurse parameter, this field must be absent.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "m.relates_to": {
          "event_id": "$asfDuShaf7Gafaw",
          "rel_type": "org.example.my_relation"
        }
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:matrix.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "next_batch": "page2_token",
  "prev_batch": "page1_token"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Event not found."
}

GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}


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.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The ID of the parent event whose child events are to be returned.

eventType string

Required: 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.

relType string

Required: The relationship type to search for.

roomId string

Required: The ID of the room containing the parent event.

query parameters
Name Type Description
dir string

Optional (default b) direction to return events from. If this is set to f, events will be returned in chronological order starting at from. If it is set to b, events will be returned in reverse chronological order, again starting at from.

One of: [b, f].

Added in v1.4

from string

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 or prev_batch token from a previous call, or a returned start token from /messages, or a next_batch token from /sync.

limit integer

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.

recurse boolean

Whether to additionally include events which only relate indirectly to the given event, i.e. events related to the given event via two or more direct relationships.

If set to false, only events which have a direct relation with the given event will be included.

If set to true, events which have an indirect relation with the given event will be included additionally up to a certain depth level. Homeservers SHOULD traverse at least 3 levels of relationships. Implementations MAY perform more but MUST be careful to not infinitely recurse.

The default value is false.

Added in v1.10

to string

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.


Responses

Status Description
200 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.
404 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).

200 response

Name Type Description
chunk [ClientEvent]

Required: 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.

next_batch string

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 string

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.

recursion_depth integer

If the recurse parameter was supplied by the client, this response field is mandatory and gives the actual depth to which the server recursed. If the client did not specify the recurse parameter, this field must be absent.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "m.relates_to": {
          "event_id": "$asfDuShaf7Gafaw",
          "rel_type": "org.example.my_relation"
        }
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:matrix.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "next_batch": "page2_token",
  "prev_batch": "page1_token"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Event not found."
}

房间

类型

[Added in v1.2]

房间可选带类型,区分功能。无类型的房间一般为会话用途。

类型有助于客户端区分功能(会话/数据型),房间类型记录于 m.room.createtype 字段,建房时以 creation_content 提供。

当前规范房间类型有:

类型可扩展,依 命名空间标识符

创建

主服务器建房时会生成 m.room.create 事件,作为事件树根;并自动设置权限等其它事件,如:

  • m.room.power_levels :设置用户及动作权限等
  • m.room.join_rules :设置加入规则

详细参见 Room Events。创建房间接口如下。

POST /_matrix/client/v3/createRoom


Create a new room with various configuration options.

The server MUST apply the normal state resolution rules when creating the new room, including checking power levels for each event. It MUST apply the events implied by the request in the following order:

  1. The m.room.create event itself. Must be the first event in the room.

  2. An m.room.member event for the creator to join the room. This is needed so the remaining events can be sent.

  3. A default m.room.power_levels event, giving the room creator (and not other members) permission to send state events. Overridden by the power_level_content_override parameter.

  4. An m.room.canonical_alias event if room_alias_name is given.

  5. Events set by the preset. Currently these are the m.room.join_rules, m.room.history_visibility, and m.room.guest_access state events.

  6. Events listed in initial_state, in the order that they are listed.

  7. Events implied by name and topic (m.room.name and m.room.topic state events).

  8. Invite events implied by invite and invite_3pid (m.room.member with membership: invite and m.room.third_party_invite).

The available presets do the following with respect to room state:

Preset join_rules history_visibility guest_access Other
private_chat invite shared can_join
trusted_private_chat invite shared can_join All invitees are given the same power level as the room creator.
public_chat public shared forbidden

The server will create a m.room.create event in the room with the requesting user as the creator, alongside other keys provided in the creation_content.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
creation_content CreationContent

Extra keys, such as m.federate, to be added to the content of the m.room.create event. The server will overwrite the following keys: creator, room_version. Future versions of the specification may allow the server to overwrite other keys.

initial_state [StateEvent]

A list of state events to set in the new room. This allows the user to override the default state events set in the new room. The expected format of the state events are an object with type, state_key and content keys set.

Takes precedence over events set by preset, but gets overridden by name and topic keys.

invite [string]

A list of user IDs to invite to the room. This will tell the server to invite everyone in the list to the newly created room.

invite_3pid [Invite3pid]

A list of objects representing third-party IDs to invite into the room.

is_direct boolean

This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid. See Direct Messaging for more information.

name string

If this is included, an m.room.name event will be sent into the room to indicate the name of the room. See Room Events for more information on m.room.name.

power_level_content_override Power Level Event Content

The power level content to override in the default power level event. This object is applied on top of the generated m.room.power_levels event content prior to it being sent to the room. Defaults to overriding nothing.

preset string

Convenience parameter for setting various default state events based on a preset.

If unspecified, the server should use the visibility to determine which preset to use. A visibility of public equates to a preset of public_chat and private visibility equates to a preset of private_chat.

One of: [private_chat, public_chat, trusted_private_chat].

room_alias_name string

The desired room alias local part. If this is included, a room alias will be created and mapped to the newly created room. The alias will belong on the same homeserver which created the room. For example, if this was set to “foo” and sent to the homeserver “example.com” the complete room alias would be #foo:example.com.

The complete room alias will become the canonical alias for the room and an m.room.canonical_alias event will be sent into the room.

room_version string

The room version to set for the room. If not provided, the homeserver is to use its configured default. If provided, the homeserver will return a 400 error with the errcode M_UNSUPPORTED_ROOM_VERSION if it does not support the room version.

topic string

If this is included, an m.room.topic event will be sent into the room to indicate the topic for the room. See Room Events for more information on m.room.topic.

visibility string

A public visibility indicates that the room will be shown in the published room list. A private visibility will hide the room from the published room list. Rooms default to private visibility if this key is not included. NB: This should not be confused with join_rules which also uses the word public.

One of: [public, private].

StateEvent
Name Type Description
content object

Required: The content of the event.

state_key string

The state_key of the state event. Defaults to an empty string.

type string

Required: The type of event to send.

Invite3pid
Name Type Description
address string

Required: The invitee’s third-party identifier.

id_access_token string

Required: An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

id_server string

Required: The hostname+port of the identity server which should be used for third-party identifier lookups.

medium string

Required: The kind of address being passed in the address field, for example email (see the list of recognised values).

Request body example

{
  "creation_content": {
    "m.federate": false
  },
  "name": "The Grand Duke Pub",
  "preset": "public_chat",
  "room_alias_name": "thepub",
  "topic": "All about happy hour"
}

Responses

Status Description
200 Information about the newly created room.
400

The request is invalid. A meaningful errcode and description error text will be returned. Example reasons for rejection include:

  • The request body is malformed (errcode set to M_BAD_JSON or M_NOT_JSON).

  • The room alias specified is already taken (errcode set to M_ROOM_IN_USE).

  • The initial state implied by the parameters to the request is invalid: for example, the user’s power_level is set below that necessary to set the room name (errcode set to M_INVALID_ROOM_STATE).

  • The homeserver doesn’t support the requested room version, or one or more users being invited to the new room are residents of a homeserver which does not support the requested room version. The errcode will be M_UNSUPPORTED_ROOM_VERSION in these cases.

200 response

Name Type Description
room_id string

Required: The created room’s ID.

{
  "room_id": "!sefiuhWgwghwWgh:example.com"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "An unknown error occurred"
}

房间别名

服务器可托管人类友好的房间别名(如 #name:server.name)。

别名以主服务器域名作用域为限,服务器一般拒绝跨域维护,因此协议不提供给外部服务器发送更新的机制。但服务器必须处理其它服务器的别名解析请求。

房间不存储自身的全部别名,权限用户可通过 m.room.canonical_alias 公布别名。别名实践中常发生漂移,请客户端校验别名链接的实际房间 ID,再做分享或使用。

GET /_matrix/client/v3/directory/room/{roomAlias}


Requests that the server resolve a room alias to a room ID.

The server will use the federation API to resolve the alias if the domain part of the alias does not correspond to the server’s own domain.

Rate-limited: No
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
roomAlias string

Required: The room alias. Its format is defined in the appendices.


Responses

Status Description
200 The room ID and other information for this alias.
400 The given roomAlias is not a valid room alias.
404 There is no mapped room ID for this room alias.

200 response

Name Type Description
room_id string

The room ID for this room alias.

servers [string]

A list of servers that are aware of this room alias.

{
  "room_id": "!abnjk1jdasj98:capuchins.com",
  "servers": [
    "capuchins.com",
    "matrix.org",
    "another.com"
  ]
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "Room alias invalid"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Room alias #monkeys:matrix.org not found."
}

PUT /_matrix/client/v3/directory/room/{roomAlias}


Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomAlias string

Required: The room alias to set. Its format is defined in the appendices.

Request body

Name Type Description
room_id string

Required: The room ID to set.

Request body example

{
  "room_id": "!abnjk1jdasj98:capuchins.com"
}

Responses

Status Description
200 The mapping was created.
400 The given roomAlias is not a valid room alias.
409 A room alias with that name already exists.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "Room alias invalid"
}

409 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "Room alias #monkeys:matrix.org already exists."
}

DELETE /_matrix/client/v3/directory/room/{roomAlias}


Remove a mapping of room alias to room ID.

Servers may choose to implement additional access control checks here, for instance that room aliases can only be deleted by their creator or a server administrator.

Note: Servers may choose to update the alt_aliases for the m.room.canonical_alias state event in the room when an alias is removed. Servers which choose to update the canonical alias event are recommended to, in addition to their other relevant permission checks, delete the alias and return a successful response even if the user does not have permission to update the m.room.canonical_alias event.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomAlias string

Required: The room alias to remove. Its format is defined in the appendices.


Responses

Status Description
200 The mapping was deleted.
404 There is no mapped room ID for this room alias.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Room alias #monkeys:example.org not found."
}

GET /_matrix/client/v3/rooms/{roomId}/aliases


Get a list of aliases maintained by the local server for the given room.

This endpoint can be called by users who are in the room (external users receive an M_FORBIDDEN error response). If the room’s m.room.history_visibility maps to world_readable, any user can call this endpoint.

Servers may choose to implement additional access control checks here, such as allowing server administrators to view aliases regardless of membership.

Note: Clients are recommended not to display this list of aliases prominently as they are not curated, unlike those listed in the m.room.canonical_alias state event.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room ID to find local aliases of.


Responses

Status Description
200 The list of local aliases for the room.
400 The given roomAlias is not a valid room alias.
403 The user is not permitted to retrieve the list of local aliases for the room.
429 This request was rate-limited.

200 response

Name Type Description
aliases [string]

Required: The server’s local aliases on the room. Can be empty.

{
  "aliases": [
    "#somewhere:example.com",
    "#another:example.com",
    "#hat_trick:example.com"
  ]
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "Room alias invalid"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not a member of the room."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

权限

本节尚在完善中。

房间权限通过 Power Level 实现。任一操作需满足所需 power level。m.room.power_levels 以状态事件记录房间内用户、各操作所需权限,默认用户 0,房主 100。用户可提升他人 power level,但不得超过自身。权限设定跨房间,有些操作如踢人、封禁、发送状态事件都需对应值。详情见 m.room.power_levels

建议 power level 对应含义如下:

  • 0 普通用户
  • 50 协管
  • 100 管理员

成员关系

必须为成员才能发送、接收事件。房间成员状态:

  • 无关:不可发送接收
  • 敲门:请求加入,等待批准
  • 邀请:已被邀请,尚未参与
  • 已加入:可正常操作
  • 被封禁:不可加入

例外情形:

  • 拒绝邀请:发送 m.room.memberleave 内容,前提已被邀请
  • 敲门加入:m.room.memberknock 内容,表示意图加入
  • 撤销敲门:发送 leave 相当于拒绝邀请

部分房间需先邀请才可加入,由 m.room.join_rules 控制:

public 自由加入

invite 需邀请

knock 要先敲门,若允许可由房间成员打招呼,请求准许

[Added in v1.2] restricted 满足指定房间成员条件或受邀请

[Added in v1.3] knock_restricted 结合 restrictedknock,即既可凭邀请/房间条件直接加入,也可敲门

状态转换流程:

成员状态机示意图

GET /_matrix/client/v3/joined_rooms


This API returns a list of the user’s current rooms.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 A list of the rooms the user is in.

200 response

Name Type Description
joined_rooms [string]

Required: The ID of each room in which the user has joined membership.

{
  "joined_rooms": [
    "!foo:example.com"
  ]
}

加入房间

POST /_matrix/client/v3/rooms/{roomId}/invite


Note that there are two forms of this API, which are documented separately. This version of the API requires that the inviter knows the Matrix identifier of the invitee. The other is documented in the third-party invites section.

This API invites a user to participate in a particular room. They do not start participating in the room until they actually join the room.

Only users currently in a particular room can invite other users to join that room.

If the user was invited to the room, the homeserver will append a m.room.member event to the room.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier (not alias) to which to invite the user.

Request body

Name Type Description
reason string

Optional reason to be included as the reason on the subsequent membership event.

Added in v1.1

user_id string

Required: The fully qualified user ID of the invitee.

Request body example

{
  "reason": "Welcome to the team!",
  "user_id": "@cheeky_monkey:matrix.org"
}

Responses

Status Description
200 The user has been invited to join the room, or was already invited to the room.
400

The request is invalid. A meaningful errcode and description error text will be returned. Example reasons for rejection include:

  • The request body is malformed (errcode set to M_BAD_JSON or M_NOT_JSON).

  • One or more users being invited to the room are residents of a homeserver which does not support the requested room version. The errcode will be M_UNSUPPORTED_ROOM_VERSION in these cases.

403

You do not have permission to invite the user to the room. A meaningful errcode and description error text will be returned. Example reasons for rejections are:

  • The invitee has been banned from the room.
  • The invitee is already a member of the room.
  • The inviter is not currently in the room.
  • The inviter’s power level is insufficient to invite users to the room.
429 This request was rate-limited.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "An unknown error occurred"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "@cheeky_monkey:matrix.org is banned from the room"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/join/{roomIdOrAlias}


Note that this API takes either a room ID or alias, unlike /rooms/{roomId}/join.

This API starts a user’s participation in a particular room, if that user is allowed to participate in that room. After this call, the client is allowed to see all current state events in the room, and all subsequent events associated with the room until the user leaves the room.

After a user has joined a room, the room will appear as an entry in the response of the /initialSync and /sync APIs.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomIdOrAlias string

Required: The room identifier or alias to join.

query parameters
Name Type Description
via [string]

The servers to attempt to join the room through. One of the servers must be participating in the room.

Added in v1.12

Request body

Name Type Description
reason string

Optional reason to be included as the reason on the subsequent membership event.

Added in v1.1

third_party_signed Third-party Signed

If a third_party_signed was supplied, the homeserver must verify that it matches a pending m.room.third_party_invite event in the room, and perform key validity checking if required by the event.

Third-party Signed
Name Type Description
mxid string

Required: The Matrix ID of the invitee.

sender string

Required: The Matrix ID of the user who issued the invite.

signatures {string: {string: string}}

Required: A signatures object containing a signature of the entire signed object.

token string

Required: The state key of the m.third_party_invite event.

Request body example

{
  "reason": "Looking for support",
  "third_party_signed": {
    "mxid": "@bob:example.org",
    "sender": "@alice:example.org",
    "signatures": {
      "example.org": {
        "ed25519:0": "some9signature"
      }
    },
    "token": "random8nonce"
  }
}

Responses

Status Description
200

The room has been joined.

The joined room ID must be returned in the room_id field.

403

You do not have permission to join the room. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The room is invite-only and the user was not invited.
  • The user has been banned from the room.
  • The room is restricted and the user failed to satisfy any of the conditions.
429 This request was rate-limited.

200 response

Name Type Description
room_id string

Required: The joined room ID.

{
  "room_id": "!d41d8cd:matrix.org"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not invited to this room."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/rooms/{roomId}/join


Note that this API requires a room ID, not alias. /join/{roomIdOrAlias} exists if you have a room alias.

This API starts a user’s participation in a particular room, if that user is allowed to participate in that room. After this call, the client is allowed to see all current state events in the room, and all subsequent events associated with the room until the user leaves the room.

After a user has joined a room, the room will appear as an entry in the response of the /initialSync and /sync APIs.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier (not alias) to join.

Request body

Name Type Description
reason string

Optional reason to be included as the reason on the subsequent membership event.

Added in v1.1

third_party_signed Third-party Signed

If supplied, the homeserver must verify that it matches a pending m.room.third_party_invite event in the room, and perform key validity checking if required by the event.

Third-party Signed
Name Type Description
mxid string

Required: The Matrix ID of the invitee.

sender string

Required: The Matrix ID of the user who issued the invite.

signatures {string: {string: string}}

Required: A signatures object containing a signature of the entire signed object.

token string

Required: The state key of the m.third_party_invite event.

Request body example

{
  "reason": "Looking for support",
  "third_party_signed": {
    "mxid": "@bob:example.org",
    "sender": "@alice:example.org",
    "signatures": {
      "example.org": {
        "ed25519:0": "some9signature"
      }
    },
    "token": "random8nonce"
  }
}

Responses

Status Description
200

The room has been joined.

The joined room ID must be returned in the room_id field.

403

You do not have permission to join the room. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The room is invite-only and the user was not invited.
  • The user has been banned from the room.
  • The room is restricted and the user failed to satisfy any of the conditions.
429 This request was rate-limited.

200 response

Name Type Description
room_id string

Required: The joined room ID.

{
  "room_id": "!d41d8cd:matrix.org"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not invited to this room."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
敲门进入房间

[Added in v1.1] [Changed in v1.3]

v1.3 支持敲门进入 restricted 房间。

如加入规则允许,外部用户可 /knock 敲门,成员可邀请(/invite)或拒绝(/kick/ban、设置 leave)。用户已在房间、已邀请、被封禁不可敲门。

同意敲门需有邀请权限,拒绝需有踢/封禁权限。

主服务器收到邀请即视为敲门被接受,无需关联至原敲门事件。服务器可自动接受邀请。

POST /_matrix/client/v3/knock/{roomIdOrAlias}


Added in v1.1

Note that this API takes either a room ID or alias, unlike other membership APIs.

This API “knocks” on the room to ask for permission to join, if the user is allowed to knock on the room. Acceptance of the knock happens out of band from this API, meaning that the client will have to watch for updates regarding the acceptance/rejection of the knock.

If the room history settings allow, the user will still be able to see history of the room while being in the “knock” state. The user will have to accept the invitation to join the room (acceptance of knock) to see messages reliably. See the /join endpoints for more information about history visibility to the user.

The knock will appear as an entry in the response of the /sync API.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomIdOrAlias string

Required: The room identifier or alias to knock upon.

query parameters
Name Type Description
via [string]

The servers to attempt to knock on the room through. One of the servers must be participating in the room.

Added in v1.12

Request body

Name Type Description
reason string

Optional reason to be included as the reason on the subsequent membership event.

Request body example

{
  "reason": "Looking for support"
}

Responses

Status Description
200

The room has been knocked upon.

The knocked room ID must be returned in the room_id field.

403

You do not have permission to knock on the room. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The room is not set up for knocking.
  • The user has been banned from the room.
404 The room could not be found or resolved to a room ID.
429 This request was rate-limited.

200 response

Name Type Description
room_id string

Required: The knocked room ID.

{
  "room_id": "!d41d8cd:matrix.org"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not allowed to knock on this room."
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "That room does not appear to exist."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
限制型房间

[Added in v1.2] [Changed in v1.3]

v1.3 起,knock_restricted 房可敲门,同理需房间支持。

限制型房间 (restricted) 在加入规则中指定 “allow conditions”。若已被邀请,规则不影响其;否则服务器判断用户是否满足任一 condition。

目前唯一可用 condition 是 m.room_membership:满足情况即已加入指定 room_id 的成员。例如:

{
  "join_rule": "restricted",
  "allow": [
    {
      "room_id": "!other:example.org",
      "type": "m.room_membership"
    }
  ]
}

离开房间

成员可离开房间(含拒绝邀请、撤回敲门),操作完成后对应房间将不会再出现在 /sync 返回中(除非用带 include_leave 的过滤器)。

如是 invite-only 房间,用户需被重新邀请才能再入。

用户也可“忘记房间”(forget),忘记后只有重新加入/被邀请才可恢复。

可被踢出(kick),需要操作者有足够权限。被踢视同主动离开,且只有非 invite-only 房才能再次加入。

POST /_matrix/client/v3/rooms/{roomId}/forget


This API stops a user remembering about a particular room.

In general, history is a first class citizen in Matrix. After this API is called, however, a user will no longer be able to retrieve history for this room. If all users on a homeserver forget a room, the room is eligible for deletion from that homeserver.

If the user is currently joined to the room, they must leave the room before calling this API.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier to forget.


Responses

Status Description
200 The room has been forgotten.
400 The user has not left the room
429 This request was rate-limited.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "User @example:matrix.org is in room !au1ba7o:matrix.org"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/rooms/{roomId}/leave


This API stops a user participating in a particular room.

If the user was already in the room, they will no longer be able to see new events in the room. If the room requires an invite to join, they will need to be re-invited before they can re-join.

If the user was invited to the room, but had not joined, this call serves to reject the invite.

The user will still be allowed to retrieve history from the room which they were previously allowed to see.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier to leave.

Request body

Name Type Description
reason string

Optional reason to be included as the reason on the subsequent membership event.

Added in v1.1

Request body example

{
  "reason": "Saying farewell - thanks for the support!"
}

Responses

Status Description
200 The room has been left.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/rooms/{roomId}/kick


Kick a user from the room.

The caller must have the required power level in order to perform this operation.

Kicking a user adjusts the target member’s membership state to be leave with an optional reason. Like with other membership changes, a user can directly adjust the target member’s state by making a request to /rooms/<room id>/state/m.room.member/<user id>.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier (not alias) from which the user should be kicked.

Request body

Name Type Description
reason string

The reason the user has been kicked. This will be supplied as the reason on the target’s updated m.room.member event.

user_id string

Required: The fully qualified user ID of the user being kicked.

Request body example

{
  "reason": "Telling unfunny jokes",
  "user_id": "@cheeky_monkey:matrix.org"
}

Responses

Status Description
200 The user has been kicked from the room.
403

You do not have permission to kick the user from the room. A meaningful errcode and description error text will be returned. Example reasons for rejections are:

  • The kicker is not currently in the room.
  • The kickee is not currently in the room.
  • The kicker’s power level is insufficient to kick users from the room.

200 response

{}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You do not have a high enough power level to kick from this room."
}
房间封禁

可封禁成员,操作是将 member 调为 ban,禁止加入、收发事件,踢出本房。必须有足够 power level,接口如下:

{
  "user_id": "<待封禁成员ID>",
  "reason": "string: 封禁原因"
}

或直接设置 membership:

{
  "membership": "ban"
}

解封需显式发送 /rooms/<room_id>/unban

POST /_matrix/client/v3/rooms/{roomId}/ban


Ban a user in the room. If the user is currently in the room, also kick them.

When a user is banned from a room, they may not join it or be invited to it until they are unbanned.

The caller must have the required power level in order to perform this operation.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier (not alias) from which the user should be banned.

Request body

Name Type Description
reason string

The reason the user has been banned. This will be supplied as the reason on the target’s updated m.room.member event.

Added in v1.1

user_id string

Required: The fully qualified user ID of the user being banned.

Request body example

{
  "reason": "Telling unfunny jokes",
  "user_id": "@cheeky_monkey:matrix.org"
}

Responses

Status Description
200 The user has been kicked and banned from the room.
403

You do not have permission to ban the user from the room. A meaningful errcode and description error text will be returned. Example reasons for rejections are:

  • The banner is not currently in the room.
  • The banner’s power level is insufficient to ban users from the room.

200 response

{}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You do not have a high enough power level to ban from this room."
}

POST /_matrix/client/v3/rooms/{roomId}/unban


Unban a user from the room. This allows them to be invited to the room, and join if they would otherwise be allowed to join according to its join rules.

The caller must have the required power level in order to perform this operation.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier (not alias) from which the user should be unbanned.

Request body

Name Type Description
reason string

Optional reason to be included as the reason on the subsequent membership event.

Added in v1.1

user_id string

Required: The fully qualified user ID of the user being unbanned.

Request body example

{
  "reason": "They've been banned long enough",
  "user_id": "@cheeky_monkey:matrix.org"
}

Responses

Status Description
200 The user has been unbanned from the room.
403

You do not have permission to unban the user from the room. A meaningful errcode and description error text will be returned. Example reasons for rejections are:

  • The unbanner’s power level is insufficient to unban users from the room.

200 response

{}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You do not have a high enough power level to unban from this room."
}

列出房间

GET /_matrix/client/v3/directory/list/room/{roomId}


Gets the visibility of a given room on the server’s public room directory.

Rate-limited: No
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room ID.


Responses

Status Description
200 The visibility of the room in the directory
404 The room is not known to the server

200 response

Name Type Description
visibility string

The visibility of the room in the directory.

One of: [private, public].

{
  "visibility": "public"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Room not found"
}

PUT /_matrix/client/v3/directory/list/room/{roomId}


Sets the visibility of a given room in the server’s public room directory.

Servers may choose to implement additional access control checks here, for instance that room visibility can only be changed by the room creator or a server administrator.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room ID.

Request body

Name Type Description
visibility string

The new visibility setting for the room. Defaults to ‘public’.

One of: [private, public].

Request body example

{
  "visibility": "public"
}

Responses

Status Description
200 The visibility was updated, or no change was needed.
404 The room is not known to the server

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Room not found"
}

GET /_matrix/client/v3/publicRooms


Lists the public rooms on the server.

This API returns paginated responses. The rooms are ordered by the number of joined members, with the largest rooms first.

Rate-limited: No
Requires authentication: No

Request

Request parameters

query parameters
Name Type Description
limit integer

Limit the number of results returned.

server string

The server to fetch the public room lists from. Defaults to the local server. Case sensitive.

since string

A pagination token from a previous request, allowing clients to get the next (or previous) batch of rooms. The direction of pagination is specified solely by which token is supplied, rather than via an explicit flag.


Responses

Status Description
200 A list of the rooms on the server.

200 response

Name Type Description
chunk [PublicRoomsChunk]

Required: A paginated chunk of public rooms.

next_batch string

A pagination token for the response. The absence of this token means there are no more results to fetch and the client should stop paginating.

prev_batch string

A pagination token that allows fetching previous results. The absence of this token means there are no results before this batch, i.e. this is the first batch.

total_room_count_estimate integer

An estimate on the total number of public rooms, if the server has an estimate.

PublicRoomsChunk
Name Type Description
avatar_url URI

The URL for the room’s avatar, if one is set.

canonical_alias string

The canonical alias of the room, if any.

guest_can_join boolean

Required: Whether guest users may join the room and participate in it. If they can, they will be subject to ordinary power level rules like any other user.

join_rule string

The room’s join rule. When not present, the room is assumed to be public. Note that rooms with invite join rules are not expected here, but rooms with knock rules are given their near-public nature.

name string

The name of the room, if any.

num_joined_members integer

Required: The number of members joined to the room.

room_id string

Required: The ID of the room.

room_type string

The type of room (from m.room.create), if any.

Added in v1.4

topic string

The topic of the room, if any.

world_readable boolean

Required: Whether the room may be viewed by guest users without joining.

{
  "chunk": [
    {
      "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE",
      "guest_can_join": false,
      "join_rule": "public",
      "name": "CHEESE",
      "num_joined_members": 37,
      "room_id": "!ol19s:bleecker.street",
      "room_type": "m.space",
      "topic": "Tasty tasty cheese",
      "world_readable": true
    }
  ],
  "next_batch": "p190q",
  "prev_batch": "p1902",
  "total_room_count_estimate": 115
}

POST /_matrix/client/v3/publicRooms


Lists the public rooms on the server, with optional filter.

This API returns paginated responses. The rooms are ordered by the number of joined members, with the largest rooms first.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
server string

The server to fetch the public room lists from. Defaults to the local server. Case sensitive.

Request body

Name Type Description
filter Filter

Filter to apply to the results.

include_all_networks boolean

Whether or not to include all known networks/protocols from application services on the homeserver. Defaults to false.

limit integer

Limit the number of results returned.

since string

A pagination token from a previous request, allowing clients to get the next (or previous) batch of rooms. The direction of pagination is specified solely by which token is supplied, rather than via an explicit flag.

third_party_instance_id string

The specific third-party network/protocol to request from the homeserver. Can only be used if include_all_networks is false.

This is the instance_id of a Protocol Instance returned by GET /_matrix/client/v3/thirdparty/protocols.

Filter
Name Type Description
generic_search_term string

An optional string to search for in the room metadata, e.g. name, topic, canonical alias, etc.

room_types [string|null]

An optional list of room types to search for. To include rooms without a room type, specify null within this list. When not specified, all applicable rooms (regardless of type) are returned.

Added in v1.4

Request body example

{
  "filter": {
    "generic_search_term": "foo",
    "room_types": [
      null,
      "m.space"
    ]
  },
  "include_all_networks": false,
  "limit": 10,
  "third_party_instance_id": "irc-freenode"
}

Responses

Status Description
200 A list of the rooms on the server.

200 response

Name Type Description
chunk [PublicRoomsChunk]

Required: A paginated chunk of public rooms.

next_batch string

A pagination token for the response. The absence of this token means there are no more results to fetch and the client should stop paginating.

prev_batch string

A pagination token that allows fetching previous results. The absence of this token means there are no results before this batch, i.e. this is the first batch.

total_room_count_estimate integer

An estimate on the total number of public rooms, if the server has an estimate.

PublicRoomsChunk
Name Type Description
avatar_url URI

The URL for the room’s avatar, if one is set.

canonical_alias string

The canonical alias of the room, if any.

guest_can_join boolean

Required: Whether guest users may join the room and participate in it. If they can, they will be subject to ordinary power level rules like any other user.

join_rule string

The room’s join rule. When not present, the room is assumed to be public. Note that rooms with invite join rules are not expected here, but rooms with knock rules are given their near-public nature.

name string

The name of the room, if any.

num_joined_members integer

Required: The number of members joined to the room.

room_id string

Required: The ID of the room.

room_type string

The type of room (from m.room.create), if any.

Added in v1.4

topic string

The topic of the room, if any.

world_readable boolean

Required: Whether the room may be viewed by guest users without joining.

{
  "chunk": [
    {
      "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE",
      "guest_can_join": false,
      "join_rule": "public",
      "name": "CHEESE",
      "num_joined_members": 37,
      "room_id": "!ol19s:bleecker.street",
      "room_type": "m.space",
      "topic": "Tasty tasty cheese",
      "world_readable": true
    }
  ],
  "next_batch": "p190q",
  "prev_batch": "p1902",
  "total_room_count_estimate": 115
}

用户数据

用户目录

POST /_matrix/client/v3/user_directory/search


Performs a search for users. The homeserver may determine which subset of users are searched, however the homeserver MUST at a minimum consider the users the requesting user shares a room with and those who reside in public rooms (known to the homeserver). The search MUST consider local users to the homeserver, and SHOULD query remote users as part of the search.

The search is performed case-insensitively on user IDs and display names preferably using a collation determined based upon the Accept-Language header provided in the request, if present.

Rate-limited: Yes
Requires authentication: Yes

Request

Request body

Name Type Description
limit integer

The maximum number of results to return. Defaults to 10.

search_term string

Required: The term to search for

Request body example

{
  "limit": 10,
  "search_term": "foo"
}

Responses

Status Description
200 The results of the search.
429 This request was rate-limited.

200 response

Name Type Description
limited boolean

Required: Indicates if the result list has been truncated by the limit.

results [User]

Required: Ordered by rank and then whether or not profile info is available.

User
Name Type Description
avatar_url URI

The avatar url, as an mxc:// URI, if one exists.

display_name string

The display name of the user, if one exists.

user_id string

Required: The user’s matrix user ID.

{
  "limited": false,
  "results": [
    {
      "avatar_url": "mxc://bar.com/foo",
      "display_name": "Foo",
      "user_id": "@foo:bar.com"
    }
  ]
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

用户资料

GET /_matrix/client/v3/profile/{userId}


Get the combined profile information for this user. This API may be used to fetch the user’s own profile information or other users; either locally or on remote homeservers.

Rate-limited: No
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose profile information to get.


Responses

Status Description
200 The profile information for this user.
403 The server is unwilling to disclose whether the user exists and/or has profile information.
404 There is no profile information for this user or this user does not exist.

200 response

Name Type Description
avatar_url URI

The user’s avatar URL if they have set one, otherwise not present.

displayname string

The user’s display name if they have set one, otherwise not present.

{
  "avatar_url": "mxc://matrix.org/SDGdghriugerRg",
  "displayname": "Alice Margatroid"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Profile lookup is disabled on this homeserver"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Profile not found"
}

GET /_matrix/client/v3/profile/{userId}/avatar_url


Get the user’s avatar URL. This API may be used to fetch the user’s own avatar URL or to query the URL of other users; either locally or on remote homeservers.

Rate-limited: No
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose avatar URL to get.


Responses

Status Description
200 The avatar URL for this user.
403 The server is unwilling to disclose whether the user exists and/or has an avatar URL.
404 There is no avatar URL for this user or this user does not exist.

200 response

Name Type Description
avatar_url URI

The user’s avatar URL if they have set one, otherwise not present.

{
  "avatar_url": "mxc://matrix.org/SDGdghriugerRg"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Profile lookup is disabled on this homeserver"
}

PUT /_matrix/client/v3/profile/{userId}/avatar_url


This API sets the given user’s avatar URL. You must have permission to set this user’s avatar URL, e.g. you need to have their access_token.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose avatar URL to set.

Request body

Name Type Description
avatar_url URI

The new avatar URL for this user.

Request body example

{
  "avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34"
}

Responses

Status Description
200 The avatar URL was set.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/profile/{userId}/displayname


Get the user’s display name. This API may be used to fetch the user’s own displayname or to query the name of other users; either locally or on remote homeservers.

Rate-limited: No
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose display name to get.


Responses

Status Description
200 The display name for this user.
403 The server is unwilling to disclose whether the user exists and/or has a display name.
404 There is no display name for this user or this user does not exist.

200 response

Name Type Description
displayname string

The user’s display name if they have set one, otherwise not present.

{
  "displayname": "Alice Margatroid"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Profile lookup is disabled on this homeserver"
}

PUT /_matrix/client/v3/profile/{userId}/displayname


This API sets the given user’s display name. You must have permission to set this user’s display name, e.g. you need to have their access_token.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose display name to set.

Request body

Name Type Description
displayname string

The new display name for this user.

Request body example

{
  "displayname": "Alice Margatroid"
}

Responses

Status Description
200 The display name was set.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

服务器行为

主服务器必须接受以下情况下的用户资料查询:

  • 与请求方共享房间的用户
  • 公开房间的成员(主服务器已知)

其它情况主服务器直接拒绝(403 + M_FORBIDDEN)。

远程用户资料查询成功时主服务器向远端请求。远端可拒绝联邦查询。

不存在的用户,主服务器可选返回 403 或 404,建议 403。

资料变更通知

因 display name 和 avatar 处处用到,信息修改时会自动广播变更:

  • 发送 join 状态 m.room.member 事件至其所在所有房间更新 displayname / avatar_url
  • 发送 m.presence 含新 displayname / avatar_url / presence

主服务器应自动完成上述通知。

此外,主服务器自有用户房间成员事件应含 displayname、avatar_url 以便客户端直接展示。

模块

模块是客户端-服务器 API 的组成部分,但并非适用于所有端点。模块定义严格区分于实验扩展或可选特性。合规服务器必须支持全部模块及相关规范(如仅面向特定客户端类型,可仅支持所需模块)。合规模块的客户端必须支持其目标特性的所有模块及规范,详见特性配置文件

特性配置文件

Matrix 支持多种客户端形态:嵌入式 IoT 至桌面客户端。并非所有设备都能实现全部功能(如无屏幕)。客户端可归入如下类型,每类包含一组必须实现的功能。必须整体实现整类配置文件所含特性。

简要表

模块 / 配置文件 网页端 移动端 桌面端 命令行 嵌入式
内容仓库 必须 必须 必须 可选 可选
直接消息 必须 必须 必须 必须 可选
忽略用户 必须 必须 必须 可选 可选
即时消息 必须 必须 必须 必须 可选
在线状态 必须 必须 必须 必须 可选
推送通知 可选 必须 可选 可选 可选
消息回执 必须 必须 必须 必须 可选
房间历史可见性 必须 必须 必须 必须 可选
房间升级 必须 必须 必须 必须 可选
第三方邀请 可选 必须 可选 可选 可选
输入状态通知 必须 必须 必须 必须 可选
用户与房间提醒 必须 必须 必须 可选 可选
VoIP 必须 必须 必须 可选 可选
客户端配置 可选 可选 可选 可选 可选
设备管理 可选 可选 可选 可选 可选
端到端加密 可选 可选 可选 可选 可选
事件注释与回应 可选 可选 可选 可选 可选
事件上下文 可选 可选 可选 可选 可选
事件替换 可选 可选 可选 可选 可选
已读未读标记 可选 可选 可选 可选 可选
访客接入 可选 可选 可选 可选 可选
内容管理策略列表 可选 可选 可选 可选 可选
OpenID 可选 可选 可选 可选 可选
引用关系 可选 可选 可选 可选 可选
内容举报 可选 可选 可选 可选 可选
富回复 可选 可选 可选 可选 可选
房间预览 可选 可选 可选 可选 可选
标签功能 可选 可选 可选 可选 可选
SSO 客户端登录/认证 可选 可选 可选 可选 可选
Secrets 可选 可选 可选 可选 可选
点对点消息 可选 可选 可选 可选 可选
服务器访问控制列表 可选 可选 可选 可选 可选
服务器管理 可选 可选 可选 可选 可选
服务器通知 可选 可选 可选 可选 可选
服务器端搜索 可选 可选 可选 可选 可选
空间 可选 可选 可选 可选 可选
贴纸消息 可选 可选 可选 可选 可选
第三方网络 可选 可选 可选 可选 可选
线程 可选 可选 可选 可选 可选

各模块具体需实现内容详见相应章节。

客户端种类

独立网页端(Web)

即以 Matrix 为主的 Web App,SPA、MPA 等。

移动端(Mobile)

专门为移动设备开发的 Matrix 客户端,通常为 App。

桌面端(Desktop)

原生桌面 GUI 客户端。

命令行(CLI)

文本终端使用的客户端。

嵌入式(Embedded)

嵌入至其他网站(如 iframe)或嵌入设备,如家用电器、汽车等,仅做少量操作,无需完整通信功能。

Application

指嵌入网页,供特定网站专用的 Matrix 客户端,通常为单一用途。

Device

指嵌入设备(如水壶、冰箱、汽车)的小型客户端,仅执行部分操作,环境受限。

即时消息

该模块增加了向房间发送易于理解的信息的支持,同时也支持为房间本身关联可读性强的信息,如房间名称和话题。

事件

m.room.message


This event is used when sending messages in a room. Messages are not limited to be text. The msgtype key outlines the type of message, e.g. text, audio, image, video, etc. The body key is text and MUST be used with every kind of msgtype as a fallback mechanism for when a client cannot render a message. This allows clients to display something even if it is just plain text.

Event type: Message event

Content

Name Type Description
body string

Required: The textual representation of this message.

msgtype string

Required: The type of message, e.g. m.image, m.text

Examples

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "<b>This is an example text message</b>",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.name


A room has an opaque room ID which is not human-friendly to read. A room alias is human-friendly, but not all rooms have room aliases. The room name is a human-friendly string designed to be displayed to the end-user. The room name is not unique, as multiple rooms can have the same room name set.

If a room has an m.room.name event with an absent, null, or empty name field, it should be treated the same as a room with no m.room.name event.

An event of this type is automatically created when creating a room using /createRoom with the name key.

Event type: State event
State key A zero-length string.

Content

Name Type Description
name string

Required: The name of the room.

Examples

{
  "content": {
    "name": "The room name"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.name",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.topic


A topic is a short message detailing what is currently being discussed in the room. It can also be used as a way to display extra information about the room, which may not be suitable for the room name. The room topic can also be set when creating a room using /createRoom with the topic key.

Event type: State event
State key A zero-length string.

Content

Name Type Description
topic string

Required: The topic text.

Examples

{
  "content": {
    "topic": "A room topic"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.topic",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.avatar


A picture that is associated with the room. This can be displayed alongside the room information.

Event type: State event
State key A zero-length string.

Content

Name Type Description
info AvatarInfo

Metadata about the image referred to in url.

url string

The URL to the image. If this property is not present, the room has no avatar. This can be useful to remove a previous room avatar.

AvatarInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

thumbnail_info ThumbnailInfo

Metadata about the image referred to in thumbnail_url.

thumbnail_url string

The URL (typically mxc:// URI) to a thumbnail of the image.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

ThumbnailInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "info": {
      "h": 398,
      "mimetype": "image/jpeg",
      "size": 31037,
      "w": 394
    },
    "url": "mxc://example.org/JWEIFJgwEIhweiWJE"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.avatar",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.pinned_events


This event is used to “pin” particular events in a room for other participants to review later. The order of the pinned events is guaranteed and based upon the order supplied in the event. Clients should be aware that the current user may not be able to see some of the events pinned due to visibility settings in the room. Clients are responsible for determining if a particular event in the pinned list is displayable, and have the option to not display it if it cannot be pinned in the client.

Event type: State event
State key A zero-length string.

Content

Name Type Description
pinned [string]

Required: An ordered list of event IDs to pin.

Examples

{
  "content": {
    "pinned": [
      "$someevent:example.org"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.pinned_events",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}
m.room.message 消息类型(msgtype)

每个 m.room.message 必须包含一个 msgtype 键,用于标识发送消息的类型。不同类型的消息有各自必须和可选的键,具体如下。如果客户端无法显示给定的 msgtype,那么应当显示备用的纯文本 body 字段。

某些消息类型支持事件内容中的 HTML,客户端应优先显示可用的 HTML。目前,m.textm.emotem.noticem.imagem.filem.audiom.videom.key.verification.request 支持额外的 format 参数 org.matrix.custom.html。当提供该字段时,必须同时提供携带 HTML 的 formatted_body。HTML 的纯文本版本则应存于 body 字段。

[Changed in v1.10] 在以往的规范版本中,formatformatted 字段仅限于 m.textm.emotem.notice 以及 m.key.verification.request。现在该列表扩展至 m.imagem.filem.audiom.video 以支持媒体标题

为防止跨站脚本攻击(XSS)、HTML 注入及类似攻击,客户端应限制渲染的 HTML 范围。强烈建议仅允许以下 HTML 标签,其余标签应拒绝使用与渲染:delh1h2h3h4h5h6blockquotepaulolsupsublibiustrongemscodehrbrdivtabletheadtbodytrthtdcaptionprespanimgdetailssummary

[Added in v1.10] 当 HTML 功能在 WHATWG HTML Living Standard 标准中被弃用时,可以无需提交 规范变更提案而弃用并用其现代等价替换之。

[Changed in v1.10] 在以往规范中,建议使用 font 标签及其 data-mx-bg-colordata-mx-colorcolor 属性。该标签现已弃用,新的消息推荐使用带有 data-mx-bg-colordata-mx-color 属性的 span 标签替代。

上述标签的所有属性均不应被允许,因为部分属性可能带来其他干扰性风险,比如添加 onclick 事件或设置过大的文本。客户端仅应允许下表中为各标签列出的属性。其中,data-mx-bg-colordata-mx-color 为列表项时,客户端应将其值(即 # 开头的 6 位十六进制颜色代码)转换为该标签相应的 CSS/属性。

标签 允许的属性
span data-mx-bg-colordata-mx-colordata-mx-spoiler(参见剧透消息)、data-mx-maths(参见数学消息
a targethref(前提是值不是相对路径,且 scheme 为 httpshttpftpmailtomagnet 中之一)
img widthheightalttitlesrc(前提是来源为 Matrix 内容 (mxc://) URI
ol start
code class(仅允许以 language- 开头的 class,以便语法高亮)
div data-mx-maths(参见数学消息

除此之外,Web 客户端应确保所有 a 标签获得 rel="noopener" 属性,以防目标页面获取当前客户端标签页/窗口的引用。

标签嵌套不得超过 100 层。客户端仅应支持其能够渲染的子集标签,对无法渲染的标签采用其他表现方式显示。例如,若客户端无法正确渲染表格,可回退为制表符分隔文本。

除了不渲染不安全的 HTML 外,客户端也不应在事件中生成不安全的 HTML。客户端同样不应生成不必要的 HTML,比如由于富文本编辑导致的多余的段落标签。事件中的 HTML 应为有效 HTML,例如有适当的闭合标签、正确的属性(结合本文档自定义说明),且整体结构合法。

[Changed in v1.13] 在更早的规范版本中,富回复 可以使用特殊标签 mx-reply。现在不再需要这样做。客户端应去除该标签及其内容。详情请参见“富回复”章节。

未来的规范会支持更强大且可扩展的消息格式化选项,例如提案 MSC1767

m.text


This message is the most basic message and is used to represent text.

Event type: Message event

Content

Name Type Description
body string

Required: The body of the message.

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

formatted_body string

The formatted version of the body. This is required if format is specified.

msgtype string

Required:

One of: [m.text].

Examples

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "<b>This is an example text message</b>",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.emote


This message is similar to m.text except that the sender is ‘performing’ the action contained in the body key, similar to /me in IRC. This message should be prefixed by the name of the sender. This message could also be represented in a different colour to distinguish it from regular m.text messages.

Event type: Message event

Content

Name Type Description
body string

Required: The emote action to perform.

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

formatted_body string

The formatted version of the body. This is required if format is specified.

msgtype string

Required:

One of: [m.emote].

Examples

{
  "content": {
    "body": "thinks this is an example emote",
    "format": "org.matrix.custom.html",
    "formatted_body": "thinks <b>this</b> is an example emote",
    "msgtype": "m.emote"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.notice


The m.notice type is primarily intended for responses from automated clients. An m.notice message must be treated the same way as a regular m.text message with two exceptions. Firstly, clients should present m.notice messages to users in a distinct manner, and secondly, m.notice messages must never be automatically responded to. This helps to prevent infinite-loop situations where two automated clients continuously exchange messages.

Event type: Message event

Content

Name Type Description
body string

Required: The notice text to send.

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

formatted_body string

The formatted version of the body. This is required if format is specified.

msgtype string

Required:

One of: [m.notice].

Examples

{
  "content": {
    "body": "This is an example notice",
    "format": "org.matrix.custom.html",
    "formatted_body": "This is an <strong>example</strong> notice",
    "msgtype": "m.notice"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.image


This message represents a single image and an optional thumbnail.

Event type: Message event

Content

Name Type Description
body string

Required: If filename is not set or the value of both properties are identical, this is the filename of the original upload. Otherwise, this is a caption for the image.

Changed in v1.10: This property can act as a caption for the image.

file EncryptedFile

Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.

filename string

The original filename of the uploaded file.

Added in v1.10

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

Added in v1.10

formatted_body string

The formatted version of the body, when it acts as a caption. This is required if format is specified.

Added in v1.10

info ImageInfo

Metadata about the image referred to in url.

msgtype string

Required:

One of: [m.image].

url string

Required if the file is unencrypted. The URL (typically mxc:// URI) to the image.

ImageInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

thumbnail_file EncryptedFile

Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted.

thumbnail_info ThumbnailInfo

Metadata about the image referred to in thumbnail_url.

thumbnail_url string

The URL (typically mxc:// URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

ThumbnailInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "filename.jpg",
    "info": {
      "h": 398,
      "mimetype": "image/jpeg",
      "size": 31037,
      "w": 394
    },
    "msgtype": "m.image",
    "url": "mxc://example.org/JWEIFJgwEIhweiWJE"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.file


This message represents a generic file.

Event type: Message event

Content

Name Type Description
body string

Required: If filename is not set or the value of both properties are identical, this is the filename of the original upload. Otherwise, this is a caption for the file.

Changed in v1.10: This property can act as a caption for the file.

file EncryptedFile

Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.

filename string

The original filename of the uploaded file.

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

Added in v1.10

formatted_body string

The formatted version of the body, when it acts as a caption. This is required if format is specified.

Added in v1.10

info FileInfo

Information about the file referred to in url.

msgtype string

Required:

One of: [m.file].

url string

Required if the file is unencrypted. The URL (typically mxc:// URI) to the file.

FileInfo
Name Type Description
mimetype string

The mimetype of the file e.g. application/msword.

size integer

The size of the file in bytes.

thumbnail_file EncryptedFile

Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted.

thumbnail_info ThumbnailInfo

Metadata about the image referred to in thumbnail_url.

thumbnail_url string

The URL to the thumbnail of the file. Only present if the thumbnail is unencrypted.

ThumbnailInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "something-important.doc",
    "filename": "something-important.doc",
    "info": {
      "mimetype": "application/msword",
      "size": 46144
    },
    "msgtype": "m.file",
    "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.audio


This message represents a single audio clip.

Event type: Message event

Content

Name Type Description
body string

Required: If filename is not set or the value of both properties are identical, this is the filename of the original upload. Otherwise, this is a caption for the audio.

Changed in v1.10: This property can act as a caption for the audio.

file EncryptedFile

Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.

filename string

The original filename of the uploaded file.

Added in v1.10

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

Added in v1.10

formatted_body string

The formatted version of the body, when it acts as a caption. This is required if format is specified.

Added in v1.10

info AudioInfo

Metadata for the audio clip referred to in url.

msgtype string

Required:

One of: [m.audio].

url string

Required if the file is unencrypted. The URL (typically mxc:// URI) to the audio clip.

AudioInfo
Name Type Description
duration integer

The duration of the audio in milliseconds.

mimetype string

The mimetype of the audio e.g. audio/aac.

size integer

The size of the audio clip in bytes.

Examples

{
  "content": {
    "body": "Bee Gees - Stayin' Alive",
    "info": {
      "duration": 2140786,
      "mimetype": "audio/mpeg",
      "size": 1563685
    },
    "msgtype": "m.audio",
    "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.location


This message represents a real-world location.

Event type: Message event

Content

Name Type Description
body string

Required: A description of the location e.g. ‘Big Ben, London, UK’, or some kind of content description for accessibility e.g. ’location attachment’.

geo_uri string

Required: A geo URI (RFC5870) representing this location.

info LocationInfo
msgtype string

Required:

One of: [m.location].

LocationInfo
Name Type Description
thumbnail_file EncryptedFile

Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted.

thumbnail_info ThumbnailInfo

Metadata about the image referred to in thumbnail_url.

thumbnail_url string

The URL to a thumbnail of the location being represented. Only present if the thumbnail is unencrypted.

ThumbnailInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "Big Ben, London, UK",
    "geo_uri": "geo:51.5008,0.1247",
    "info": {
      "thumbnail_info": {
        "h": 300,
        "mimetype": "image/jpeg",
        "size": 46144,
        "w": 300
      },
      "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
    },
    "msgtype": "m.location"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.video


This message represents a single video clip.

Event type: Message event

Content

Name Type Description
body string

Required: If filename is not set or the value of both properties are identical, this is the filename of the original upload. Otherwise, this is a caption for the video.

Changed in v1.10: This property can act as a caption for the video.

file EncryptedFile

Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.

filename string

The original filename of the uploaded file.

Added in v1.10

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

Added in v1.10

formatted_body string

The formatted version of the body, when it acts as a caption. This is required if format is specified.

Added in v1.10

info VideoInfo

Metadata about the video clip referred to in url.

msgtype string

Required:

One of: [m.video].

url string

Required if the file is unencrypted. The URL (typically mxc:// URI) to the video clip.

VideoInfo
Name Type Description
duration integer

The duration of the video in milliseconds.

h integer

The height of the video in pixels.

mimetype string

The mimetype of the video e.g. video/mp4.

size integer

The size of the video in bytes.

thumbnail_file EncryptedFile

Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted.

thumbnail_info ThumbnailInfo

Metadata about the image referred to in thumbnail_url.

thumbnail_url string

The URL (typically mxc:// URI) to an image thumbnail of the video clip. Only present if the thumbnail is unencrypted.

w integer

The width of the video in pixels.

ThumbnailInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "Gangnam Style",
    "info": {
      "duration": 2140786,
      "h": 320,
      "mimetype": "video/mp4",
      "size": 1563685,
      "thumbnail_info": {
        "h": 300,
        "mimetype": "image/jpeg",
        "size": 46144,
        "w": 300
      },
      "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
      "w": 480
    },
    "msgtype": "m.video",
    "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

客户端应验证收到事件的结构,确保所需字段存在且类型正确。对于格式错误的事件,可以选择丢弃或向用户显示占位提示消息。被修订(redacted)的 m.room.message 事件必须从客户端删除,可以用占位文本(如“[REDACTED]”)替换,或直接从消息视图移除。

带有附件的事件(如 m.imagem.file)应使用内容仓库模块上传(如可用)。所得的 mxc:// URI 可用于 url 字段。

客户端可通过 info.thumbnail_url 字段为附件带上客户端生成的缩略图。该缩略图也应为 mxc:// URI。呈现附带附件的事件时,客户端可直接使用缩略图,或者通过内容仓库模块请求 homeserver 基于原始附件生成缩略图。

发送消息时的推荐做法

在发送失败时,客户端应使用指数退避算法重试请求,重试时间 T 为一段时间,建议不超过 5 分钟。超时后客户端应停止重试,并将消息标记为“未发送”。用户应能够手动重新发送未发送消息。

用户可能会一次输入并快速发送多条消息。客户端应保持用户发送消息的顺序,这意味着应等待上一请求响应后再发送下一个请求。这可能导致“队头阻塞”。为减轻此影响,应按房间分别使用队列而非全局队列,因为顺序仅在单一房间内有意义,房间间无需严格顺序。

本地回显(Local Echo)

用户点击“发送”按钮时,消息应立即在消息视图中显示,哪怕消息正在发送中。这一过程称为“本地回显”。客户端应实现本地消息回显。客户端可采用不同展示方式显示尚未被服务器处理的消息。当服务器响应后应移除该特殊格式。

客户端需要能将其发送的消息和从事件流中收到的同一消息进行匹配。从事件流收到的同一消息的回显称为“远程回显”。本地回显和远程回显都要能被识别为相同消息,以防止重复显示。理想情况下,这一过程对用户透明:UI 从本地回显切换为远程回显时不会闪烁。通过使用用于发送事件的事务 ID,可减少切换时的闪烁。事务 ID 会作为收到事件时 unsigned 数据中的 transaction_id 字段返回。

如果客户端无法使用事务 ID,那么当远程回显在消息发送请求完成之前到达事件流时,很可能会出现闪烁。在这种情况下,事件在消息发送请求完成、客户端获得事件 ID 之前就到了,导致无法将其识别为远程回显。这样客户端在一段时间内(取决于服务器响应速度)会同时显示两条消息。请求完成后,客户端可通过查找重复事件 ID 移除多余事件。

计算用户的显示名

客户端可能希望在成员列表或消息发送时展示房间成员的可读型显示名。然而,不同成员可能出现显示名冲突。显示名在展示给用户前必须唯一化处理,以防止冒充其他用户。

为确保客户端间一致处理,推荐使用如下算法为指定用户计算唯一显示名:

  1. 检查相关用户的 m.room.member 状态事件。
  2. 若该状态事件无 displayname 字段或该字段为 null,则用其原始用户 ID 作为显示名。否则:
  3. m.room.member 事件中的 displayname 在房间中所有 membership: joinmembership: invite 成员里是唯一的,则用该 displayname 作为可见显示名。否则:
  4. displayname 不唯一,应结合用户 ID 做唯一化处理,例如“显示名 (@id:homeserver.org)”。

开发者在实现该算法时需注意:

  • 一名成员的显示名有可能因其他成员状态变化而变化。例如,若 @user1:matrix.org 在房间中显示为 Alice,当 @user2:example.com 也以 Alice 加入该房间时,两名用户都必须使用唯一化后的显示名。相反,若其中一名用户更改显示名致不再冲突,两者又可拥有自己原先的显示名。客户端需注意并确保对受影响成员正确重命名。
  • 房间显示名也可能因成员名单变化而受影响。因为房间名有时基于用户显示名派生(见计算房间显示名)。
  • 若全量遍历成员列表以查重显示名,则会导致 O(N^2) 复杂度,该实现对房间成员众多时很低效。建议客户端维护一个从 displayname 到使用该名成员列表的哈希表,以高效判断是否需唯一化。
随消息同步展示成员信息

客户端可能希望显示发送消息成员的显示名与头像 URL。可通过检查该用户 ID 的 m.room.member 状态事件获取(参见计算用户显示名)。

在用户分页浏览历史记录时,客户端可能希望展示成员的历史显示名与头像 URL。由于分页时会返回旧的 m.room.member 事件,因此可以实现该功能。一般做法是同时维护两组房间状态:旧状态和当前状态。随着新事件到达和/或用户回溯浏览,这两组状态会逐渐分化:新事件更新当前状态,分页事件更新旧状态。当分页事件顺序处理时,旧状态即为消息发送时的房间状态。历史显示名和头像 URL 可由此设置。

计算房间显示名

客户端可能希望显示房间的可读型名称。命名方式有多种选择。为保持不同客户端之间房间命名一致,推荐按照如下算法选择房间名:

  1. 若房间具有 m.room.name 状态事件且其 name 字段非空,则采用该字段给出的名称。
  2. 若房间有 m.room.canonical_alias 状态事件且该 alias 字段有效,则使用之。请注意,客户端在计算房间名时应避免使用 alt_aliases
  3. 如果以上条件都不满足,应根据房间成员组合房间名。客户端应考虑除当前用户外的 m.room.member 事件(定义如下)。
    1. 若房间 m.heroes 数量大于等于 m.joined_member_count + m.invited_member_count - 1,则可利用英雄成员的事件计算用户显示名(必要时唯一化)并拼接。比如,客户端可选择展示“Alice, Bob,以及 Charlie (@charlie:example.org)”作为房间名。客户端可根据用户体验选择限制用于生成房间名的成员数量。
    2. 若英雄成员数少于 m.joined_member_count + m.invited_member_count - 1,且总成员数大于 1,则应用英雄成员计算显示名(必要时唯一化),拼接后加上剩余成员人数。例如,“Alice、Bob 及其他 1234 位成员”。
    3. 若成员总数(加入和被邀请之和)小于等于 1(表明该成员为唯一成员),则依据上述规则显示房间为空。例如,“空房间(曾为 Alice)”、“空房间(曾为 Alice 及 1234 位成员)”或无成员时显示“空房间”。

客户端用 m.heroes 计算房间名时应对各国语言进行国际化处理。生成房间名时,客户端应尽量使用不少于 5 名英雄成员,但可根据实际需求调整数量以配合用户体验。

剧透消息

[Added in v1.1]

消息中的部分内容可通过剧透形式在视觉上对用户隐藏。这不影响服务器对事件内容的存储,仅是在视觉上提示用户相关内容可能会暴露重要信息,导致“剧透”。

发送剧透消息时,客户端必须使用 formatted_body,即上文描述的 org.matrix.custom.html 格式。因此,支持剧透的任意 msgtype 都须支持该格式。

剧透内容包裹在 span 标签中,原因(可选)放在 data-mx-spoiler 属性里。若无原因,属性值可留空或未定义,但该属性不能省略。

一个剧透消息示例:

{
  "msgtype": "m.text",
  "format": "org.matrix.custom.html",
  "body": "Alice [剧透](mxc://example.org/abc123) 在电影里。",
  "formatted_body": "Alice <span data-mx-spoiler>最终幸福地生活下去</span> 在电影里。"
}

若提供原因,则如下:

{
  "msgtype": "m.text",
  "format": "org.matrix.custom.html",
  "body": "Alice [健康剧透](mxc://example.org/abc123) 在电影里。",
  "formatted_body": "Alice <span data-mx-spoiler='健康'>最终幸福地生活下去</span> 在电影里。"
}

发送剧透时,客户端应如上示例在 body 字段提供包含原因的备用内容。备用 body 字段不应包含剧透正文,因为 body 可能被文本类客户端或通知直接显示。为防止剧透内容被泄露,强烈推荐客户端首先将剧透正文上传至媒体仓库,然后以 markdown 链接形式引用对应 mxc:// URI,如上述示例。

客户端应区别渲染剧透内容,并以某种显式交互提示。例如,可将剧透文本模糊化,提示用户点击后显示。

媒体标题

[Added in v1.10]

媒体消息(包括 m.imagem.filem.audiom.video)可包含题注,以补充说明媒体内容。

发送标题时,客户端必须同时使用 filenamebody 字段,formatted_bodyorg.matrix.custom.html 格式为可选。

如存在 filename 字段,且其与 body 不同,则将 body 视为题注,否则 body 视为文件名。formatformatted_body 仅用于题注。

在旧规范中,body 字段通常用于上传文件名,而 filename 字段仅出现在 m.file 上且用法一致。

媒体消息附带题注示例:

{
    "msgtype": "m.image",
    "url": "mxc://example.org/abc123",
    "filename": "dog.jpg",
    "body": "这是一张~~猫咪~~照片 :3",
    "format": "org.matrix.custom.html",
    "formatted_body": "这是一张 <s>猫咪</s> 照片 :3",
    "info": {
        "w": 479,
        "h": 640,
        "mimetype": "image/jpeg",
        "size": 27253
    },
    "m.mentions": {}
}

客户端必须与媒体一起渲染标题,并应优先渲染其格式化形式。

数学消息

[Added in v1.11]

用户可能希望在消息中发送数学符号或公式。

发送数学公式时,客户端必须使用 formatted_body,即采用上述 org.matrix.custom.html 格式。任何可用该格式的 msgtype 均可支持数学形式。

数学内容根据是否需要行内显示,使用 spandiv 标签。用 data-mx-maths 属性书写 LaTeX 格式的公式。

标签内容为不能渲染 LaTeX 的客户端备用显示。可用图片、HTML 近似表示或原始 LaTeX 源文本作为备用。若用图片作为备用,发送方应注意接收端可能背景色不同所带来的显示问题。body 字段应包含文本表示的公式。

数学消息示例:

{
  "msgtype": "m.text",
  "format": "org.matrix.custom.html",
  "body": "这是一个方程:sin(x)=a/b。",
  "formatted_body": "这是一个方程:<span data-mx-maths=\"\\sin(x)=\\frac{a}{b}\">sin(<i>x</i>)=<sup><i>a</i></sup>/<sub><i>b</i></sub></span>"
}

LaTeX 语法定义不完整且有多种扩展,若客户端遇到无法渲染的语法,应优先显示备用内容。但客户端最低应支持LaTeX2e 的数学命令及 TeX 数学命令(部分命令因安全风险可例外)。

总的说来,LaTeX 给客户端带来了安全处理压力。部分命令(如可创建宏的命令)具潜在风险。客户端应拒绝处理此类命令,或确保安全处理(如限制递归)。客户端应以白名单方式只允许已知安全命令,而非黑名单拒绝已知不安全命令。

因此,客户端在未安全隔离环境下,不应直接调用 LaTeX 编译器渲染数学表达式,因为相关可执行文件并未设计处理不可信输入。有些 LaTeX 渲染库适合,仅允许部分 LaTeX 并限制递归深度。

服务器行为

HomeServer 在收到不包含 msgtype 键,或无文本型 body 键的 m.room.message 事件时,应拒绝请求并返回 400 HTTP 状态码。

安全注意事项

使用本模块发送的消息不会加密,端到端加密(E2E)仍在开发中(详见 E2E 模块)。

客户端应对所有显示的键进行不安全 HTML 的过滤,以防止跨站脚本(XSS)攻击。这包括房间名称和话题。

富回复(Rich replies)

富回复是一种特殊类型的关系,它有效地引用了被引用事件,供客户端以其所希望的方式进行渲染或处理。富回复通常与 m.room.message 事件一起使用。

[Changed in v1.3] 在规范 v1.3 之前,富回复仅限于表示为 HTML 格式正文的 m.room.message 事件。从 v1.3 开始,这一限制被解除,富回复现在可以应用于所有事件类型,无需再强制要求包含 HTML 格式正文。

此外,从 v1.3 起,富回复可以引用任何其他事件类型。此前,富回复只能引用另一条 m.room.message 事件。

[Changed in v1.13] 在规范早期版本中,富回复可在 body(通过前缀序列)和 formatted_body(通过自定义 HTML 元素)中包含原始消息的回退表示,供不支持富回复的客户端使用。目前已不再要求如此,但客户端仍在渲染事件前移除这些回退内容。

要去除 body 中的回退内容,客户端应逐行遍历字符串,移除以回退前缀序列(> ,包括尾随空格)开始的所有行,遇到不含该前缀的行时停止处理。

要去除 formatorg.matrix.custom.htmlm.room.message 事件的 formatted_body 回退内容:如果 formatted_body<mx-reply> 起始标签开头,客户端应移除整个 <mx-reply> 元素。

虽然富回复与另一个事件形成关系,但它们并不使用 rel_type 来建立这种关系。相反,采用名为 m.in_reply_to 的子键来描述回复关系,从而使 m.relates_to 的其它属性可被用于描述该事件的主关系。这意味着,如果一个事件只是单纯回复另一事件而无其它关系,m.relates_to 中的 rel_typeevent_id 属性变为可选

一个回复示例:

{
  "content": {
    "m.relates_to": {
      "m.in_reply_to": {
        "event_id": "$another_event"
      }
    },
    "body": "That sounds like a great idea!"
  },
  // 事件所需的其他字段
}

请注意,m.in_reply_to 对象中的 event_id 具有与其直接位于 m.relates_to 下时相同的要求。

提及被回复用户

为了通知用户被回复,建议在回复中包括被回复事件的 sender 以及该事件中提及的所有用户。更多信息请参见用户和房间提及

包含原始发送者及其他用户提及的示例:

{
  "content": {
    "m.relates_to": {
      "m.in_reply_to": {
        "event_id": "$another_event"
      }
    },
    "body": "That sounds like a great idea!",
    "m.mentions": {
      "user_ids": [
        // $another_event 的发送者
        "@alice:example.org",
        // 从 $another_event 的 m.mentions 属性中复制的另一个 Matrix ID
        "@bob:example.org"
      ]
    }
  },
  // 事件所需的其他字段
}

语音通信(VoIP)

本模块描述了房间内两位用户如何建立语音通信(VoIP)通话。语音和视频通话均基于 WebRTC 1.0 标准构建。通话信令通过向房间发送消息事件来实现。在本规范版本中,仅支持双方通信(如两点对两点,或点对多点会议设备)。虽然通话可在包含多位成员的房间中发起,但同一时间仅允许两台设备参与通话。

所有 VoIP 事件均包含一个 version 字段。该字段用于判断设备是否支持此新版本的协议。例如,客户端可利用该字段判断是否应期待来自对方的 m.call.select_answer 事件。如果客户端接收到的事件 version 字段不是 0"1"(包括如数值型 1),则应视同其 version == "1" 处理。

需注意,这意味着未来任何版本的 VoIP 事件均应保持向后兼容性。如有必要引入非兼容性新规范,则将采用一套独立的事件类型。

通话方标识符

每当客户端首次参与新通话时,应为自身生成一个 party_id,在通话期间一直使用。此标识符应足够长,确保即使多设备同时生成应答,其间发生冲突的概率极低:建议使用 8 个大小写字母+数字字符。通话方通过 (user_id, party_id) 元组进行识别。

客户端将包含该 party_id 字段,并放置于所有 VoIP 事件内容的顶层,包括 m.call.invite。客户端用此字段识别自身事件的远端回显:由于用户可能与自己通话,无法简单地忽略来自自身用户的事件。此外,该字段还能区分不同客户端对同一邀请发出的不同应答,并将 m.call.candidates 事件与相应的应答/邀请进行匹配。

客户端实现可选择使用端到端加密中使用的设备 ID,用作此目的;或者可为每次通话生成不同 ID,以避免在未加密房间中泄露使用设备信息,或隐藏单一设备(即 Access Token)被用于多个通话方信令发送等信息。

party_id 的语法定义见下文

礼让规则

根据 WebRTC 完美协商示例,在重新协商过程中存在礼让(politeness)规则。被叫方始终为礼让方。在碰撞(glare)情况下,通话方的礼让状态由是采纳呼入通话还是主动呼叫决定:如果客户端舍弃本地呼出而采用呼入通话,则其为礼让方。

通话事件存活性

m.call.invite 中包含 lifetime 字段,指示邀约有效的时长。收到邀请后,客户端应结合事件同步响应中的 age 字段与自接收到该事件以来的时间,判断邀约是否依然有效。使用 age 字段可确保客户端设备错误时钟不会导致通话异常。

若邀约有效且在用户可接受通话期间保持有效,应提示有来电。用户可接受通话的时长可由不同客户端自行决定,例如在锁定的移动设备上,可以比在解锁的桌面设备上更长。

在处理完整个同步响应(sync response)并(对于加密房间)尝试解密该房间全部加密事件后,客户端才应提示来电。这样可以避免同步响应中含有随后指示通话已挂断、被拒绝或已被他处接听的事件时,重复提示来电。

若客户端启动后,在处理本地已存储事件后,发现仍有有效的邀约,应在与 homeserver 完成一次同步后再予以提示。

建议的最小有效时长为 90 秒——这样可确保用户有充足时间接听来电。

ICE 候选(Candidate)批量发送

客户端应设法只发送少量候选事件,具体指引如下:

  • 在邀请/应答事件本身中,应立即或几乎立即发现的 ICE 候选(例如 host 类型 candidate)。如能在短时间内收集到服务器反射或中继 candidate,应一并发送。建议初始延迟约 200ms。
  • 之后,客户端应等待一段时间以收集更多候选,实现批量发送,而非每获一个立刻发送。建议在发送邀请后等待 2 秒,或发送应答后等待 500ms(因发送邀请后,客户端本就等待用户接听,可利用此延迟)。

结束候选通知(End-of-candidates)

值为空字符串的 ICE 候选表示不会再发送新的 ICE 候选。客户端必须在 m.call.candidates 消息中发送此类候选。虽然 WebRTC 规范要求浏览器生成此候选,但截止目前,并非所有浏览器都实现(Chrome 不生成,但会产生 icegatheringstatechange 事件)。候选生成结束时,客户端应立即发送全部候选,而不应再等待上文时间间隔。这可方便桥接到不支持逐步 ICE(trickle ICE)协议时对候选的批量处理。

DTMF

Matrix 客户端可按 WebRTC 规范发送 DTMF。截至 2020 年 8 月,WebRTC 标准尚不支持接收 DTMF,但 Matrix 客户端可接收并解析 RTP 负载中的 DTMF 信号。

VoIP 标识符的语法

call_idparty_id 必须遵循不透明标识符语法

离开房间时的行为

若客户端检测到正在通话的用户离开房间,应将其视作所有正在进行中的通话的挂断事件。对于发送邀约而被邀请方离开房间的情形,规范未做硬性规定,但若房间内已无可接听用户,客户端可选择将其视作被拒绝(如仅剩发送方本人,或邀约的 invitee 字段被设置后未被接听)。

历史通话回溯时亦应如此处理。

支持的编解码器

Matrix 规范未强制指定特定音视频编解码器,完全遵循 WebRTC 规范。兼容的 Matrix VoIP 客户端将像被支持的“浏览器”一样,根据所支持的编解码器及其变体运作。需遵循最新的 WebRTC 规范版本,因此客户端应及时跟进 WebRTC 规范的新版本,无论 Matrix 规范是否变更。

事件

通用字段

Call event


The content of all call events shares a set of common fields: those of room events and some additional VoIP specific fields.

Name Type Description
call_id string

Required: The ID of the call this event relates to.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

事件

m.call.invite


This event is sent by the caller when they wish to establish a call.

Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

invitee string

The ID of the user being called. If omitted, any user in the room can answer.

Added in v1.7

lifetime integer

Required: The time in milliseconds that the invite is valid for. Once the invite age exceeds this value, clients should discard it. They should also no longer show the call as awaiting an answer in the UI.

offer Offer

Required: The session description object

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

sdp_stream_metadata {string: StreamMetadata}

Metadata describing the streams that will be sent.

This is a map of stream ID to metadata about the stream.

Added in v1.10

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Offer
Name Type Description
sdp string

Required: The SDP text of the session description.

type string

Required: The type of session description.

One of: [offer].

StreamMetadata
Name Type Description
audio_muted boolean

Whether the audio track in the stream is muted.

Defaults to false if not present.

Added in v1.11

purpose string

Required: The purpose of the stream.

The possible values are:

  • m.usermedia: Stream that contains the webcam and/or microphone tracks.
  • m.screenshare: Stream with the screen-sharing tracks.

One of: [m.usermedia, m.screenshare].

video_muted boolean

Whether the video track in the stream is muted.

Defaults to false if not present.

Added in v1.11

Examples

{
  "content": {
    "call_id": "12345",
    "lifetime": 60000,
    "offer": {
      "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
      "type": "offer"
    },
    "party_id": "67890",
    "sdp_stream_metadata": {
      "271828182845": {
        "purpose": "m.screenshare"
      },
      "314159265358": {
        "purpose": "m.usermedia"
      }
    },
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.invite",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.candidates


This event is sent by callers after sending an invite and by the callee after answering. Its purpose is to give the other party additional ICE candidates to try using to communicate.

Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

candidates [Candidate]

Required: Array of objects describing the candidates.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Candidate
Name Type Description
candidate string

Required: The SDP ‘a’ line of the candidate.

If this is an end-of-candidates candidate, this is the empty string.

sdpMLineIndex number

The index of the SDP ’m’ line this candidate is intended for.

At least one of sdpMid or sdpMLineIndex is required, unless this an end-of-candidates candidate.

sdpMid string

The SDP media type this candidate is intended for.

At least one of sdpMid or sdpMLineIndex is required, unless this an end-of-candidates candidate.

Examples

{
  "content": {
    "call_id": "12345",
    "candidates": [
      {
        "candidate": "candidate:863018703 1 udp 2122260223 10.9.64.156 43670 typ host generation 0",
        "sdpMLineIndex": 0,
        "sdpMid": "audio"
      }
    ],
    "party_id": "67890",
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.candidates",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.reject


Added in v1.7

If the m.call.invite event has version "1", a client wishing to reject the call sends an m.call.reject event. This rejects the call on all devices, but if the calling device sees an answer before the reject, it disregards the reject event and carries on. The reject has a party_id just like an answer, and the caller sends a select_answer for it just like an answer. If another client had already sent an answer and sees the caller select the reject response instead of its answer, it ends the call. If the m.call.invite event has version 0, the callee sends an m.call.hangup event. If the calling user chooses to end the call before setup is complete, the client sends m.call.hangup as previously.

Note that, unlike m.call.hangup, this event has no reason field: the rejection of a call is always implicitly because the user chose not to answer it.

Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Examples

{
  "content": {
    "call_id": "12345",
    "party_id": "67890",
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.reject",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.answer


This event is sent by the callee when they wish to answer the call.

Event type: Message event

Content

CallEvent
Name Type Description
answer Answer

Required: The session description object

call_id string

Required: The ID of the call this event relates to.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

sdp_stream_metadata {string: StreamMetadata}

Metadata describing the streams that will be sent.

This is a map of stream ID to metadata about the stream.

Added in v1.10

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Answer
Name Type Description
sdp string

Required: The SDP text of the session description.

type string

Required: The type of session description.

One of: [answer].

StreamMetadata
Name Type Description
audio_muted boolean

Whether the audio track in the stream is muted.

Defaults to false if not present.

Added in v1.11

purpose string

Required: The purpose of the stream.

The possible values are:

  • m.usermedia: Stream that contains the webcam and/or microphone tracks.
  • m.screenshare: Stream with the screen-sharing tracks.

One of: [m.usermedia, m.screenshare].

video_muted boolean

Whether the video track in the stream is muted.

Defaults to false if not present.

Added in v1.11

Examples

{
  "content": {
    "answer": {
      "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
      "type": "answer"
    },
    "call_id": "12345",
    "party_id": "67890",
    "sdp_stream_metadata": {
      "271828182845": {
        "purpose": "m.screenshare"
      },
      "314159265358": {
        "purpose": "m.usermedia"
      }
    },
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.answer",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.select_answer


Added in v1.7

This event is sent by the caller’s client once it has decided which other client to talk to, by selecting one of multiple possible incoming m.call.answer events. Its selected_party_id field indicates the answer it’s chosen. The call_id and party_id of the caller is also included. If the callee’s client sees a select_answer for an answer with party ID other than the one it sent, it ends the call and informs the user the call was answered elsewhere. It does not send any events. Media can start flowing before this event is seen or even sent. Clients that implement previous versions of this specification will ignore this event and behave as they did before.

Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

selected_party_id string

Required: The party_id field from the answer event that the caller chose.

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Examples

{
  "content": {
    "call_id": "12345",
    "party_id": "67890",
    "selected_party_id": "111213",
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.select_answer",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.negotiate


Added in v1.7

Provides SDP negotiation semantics for media pause, hold/resume, ICE restarts and voice/video call up/downgrading. Clients should implement and honour hold functionality as per WebRTC’s recommendation.

If both the invite event and the accepted answer event have version equal to "1", either party may send m.call.negotiate with a description field to offer new SDP to the other party. This event has call_id with the ID of the call and party_id equal to the client’s party ID for that call. The caller ignores any negotiate events with party_id + user_id tuple not equal to that of the answer it accepted and the callee ignores any negotiate events with party_id + user_id tuple not equal to that of the caller. Clients should use the party_id field to ignore the remote echo of their own negotiate events.

This has a lifetime field as in m.call.invite, after which the sender of the negotiate event should consider the negotiation failed (timed out) and the recipient should ignore it.

The description field is the same as the offer field in m.call.invite and answer field in m.call.answer and is an RTCSessionDescriptionInit object as per https://www.w3.org/TR/webrtc/#dom-rtcsessiondescriptioninit.

Once an m.call.negotiate event is received, the client must respond with another m.call.negotiate event, with the SDP answer (with "type": "answer") in the description property.

In the m.call.invite and m.call.answer events, the offer and answer fields respectively are objects of type RTCSessionDescriptionInit. Hence the type field, whilst redundant in these events, is included for ease of working with the WebRTC API and is mandatory. Receiving clients should not attempt to validate the type field, but simply pass the object into the WebRTC API.

Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

description Description

Required: The session description object

lifetime integer

Required: The time in milliseconds that the negotiation is valid for. Once the negotiation age exceeds this value, clients should discard it.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

sdp_stream_metadata {string: StreamMetadata}

Metadata describing the streams that will be sent.

This is a map of stream ID to metadata about the stream.

Added in v1.10

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Description
Name Type Description
sdp string

Required: The SDP text of the session description.

type string

Required: The type of session description.

One of: [offer, answer].

StreamMetadata
Name Type Description
audio_muted boolean

Whether the audio track in the stream is muted.

Defaults to false if not present.

Added in v1.11

purpose string

Required: The purpose of the stream.

The possible values are:

  • m.usermedia: Stream that contains the webcam and/or microphone tracks.
  • m.screenshare: Stream with the screen-sharing tracks.

One of: [m.usermedia, m.screenshare].

video_muted boolean

Whether the video track in the stream is muted.

Defaults to false if not present.

Added in v1.11

Examples

{
  "content": {
    "call_id": "12345",
    "description": {
      "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
      "type": "offer"
    },
    "lifetime": 10000,
    "party_id": "67890",
    "sdp_stream_metadata": {
      "271828182845": {
        "purpose": "m.screenshare"
      },
      "314159265358": {
        "purpose": "m.usermedia"
      }
    },
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.negotiate",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.sdp_stream_metadata_changed


Added in v1.11

This event is sent by callers when they wish to update a stream’s metadata but no negotiation is required.

Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

sdp_stream_metadata {string: StreamMetadata}

Required: Metadata describing the streams that will be sent.

This is a map of stream ID to metadata about the stream.

Added in v1.10

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

StreamMetadata
Name Type Description
audio_muted boolean

Whether the audio track in the stream is muted.

Defaults to false if not present.

Added in v1.11

purpose string

Required: The purpose of the stream.

The possible values are:

  • m.usermedia: Stream that contains the webcam and/or microphone tracks.
  • m.screenshare: Stream with the screen-sharing tracks.

One of: [m.usermedia, m.screenshare].

video_muted boolean

Whether the video track in the stream is muted.

Defaults to false if not present.

Added in v1.11

Examples

{
  "content": {
    "call_id": "1414213562373095",
    "party_id": "1732050807568877",
    "sdp_stream_metadata": {
      "2311546231": {
        "audio_muted:": true,
        "purpose": "m.usermedia",
        "video_muted": true
      }
    },
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.sdp_stream_metadata_changed",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.call.hangup


Sent by either party to signal their termination of the call. This can be sent either once the call has has been established or before to abort the call.

The meanings of the reason field are as follows:

  • ice_failed: ICE negotiation has failed and a media connection could not be established.
  • ice_timeout: The connection failed after some media was exchanged (as opposed to ice_failed which means no media connection could be established). Note that, in the case of an ICE renegotiation, a client should be sure to send ice_timeout rather than ice_failed if media had previously been received successfully, even if the ICE renegotiation itself failed.
  • invite_timeout: The other party did not answer in time.
  • user_hangup: Clients must now send this code when the user chooses to end the call, although for backwards compatibility with version 0, a clients should treat an absence of the reason field as user_hangup.
  • user_media_failed: The client was unable to start capturing media in such a way that it is unable to continue the call.
  • user_busy: The user is busy. Note that this exists primarily for bridging to other networks such as the PSTN. A Matrix client that receives a call whilst already in a call would not generally reject the new call unless the user had specifically chosen to do so.
  • unknown_error: Some other failure occurred that meant the client was unable to continue the call rather than the user choosing to end it.
Event type: Message event

Content

CallEvent
Name Type Description
call_id string

Required: The ID of the call this event relates to.

party_id string

Required: This identifies the party that sent this event. A client may choose to re-use the device ID from end-to-end cryptography for the value of this field.

Added in v1.7

reason string

Required: Reason for the hangup. Note that this was optional in previous previous versions of the spec, so a missing value should be treated as user_hangup.

One of: [ice_timeout, ice_failed, invite_timeout, user_hangup, user_media_failed, user_busy, unknown_error].

Changed in v1.7: Additional values were added.

version string

Required: The version of the VoIP specification this message adheres to. This specification is version 1. This field is a string such that experimental implementations can use non-integer versions. This field was an integer in the previous spec version and implementations must accept an integer 0.

Examples

{
  "content": {
    "call_id": "12345",
    "party_id": "67890",
    "reason": "user_hangup",
    "version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.hangup",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

通话建立流程如下,双方通过消息事件进行通信:

    呼叫方                    被叫方
    [发起呼叫]
    m.call.invite ----------->  
    m.call.candidate -------->
    [..candidates..] -------->
                          [接听来电]
         <--------------- m.call.answer
    m.call.select_answer ----------->
     [通话正在进行中]
         <--------------- m.call.hangup

或通话被拒绝时:

    呼叫方                      被叫方
    m.call.invite ------------>
    m.call.candidate --------->
    [..candidates..] --------->
                           [拒绝通话]
             <-------------- m.call.hangup

通话协商遵循 WebRTC 规范进行。

面对来电,客户端可采取多种操作:

  • 发送 m.call.answer,尝试接听通话。
  • 主动在所有设备上拒绝通话:如上图,发送 m.call.reject,则所有用户设备均停止响铃,并通知呼叫方其来电被拒。
  • 忽略通话:不发送任何事件,仅本地停止通话提示。用户的其他设备仍会继续响铃,呼叫方设备继续显示响铃,若无设备响应,通话将自动超时。
多流(Streams)

客户端可在一次 VoIP 通话中发送多路流。应通过在 m.call.invitem.call.answer 以及 m.call.negotiate 事件中加入 sdp_stream_metadata 属性来区分流。当元数据发生变更但无需重新协商时,可发送 m.call.sdp_stream_metadata_changed 事件。

推荐客户端对于带 audio_muted 字段且值设为 true 的来流,不要本地关闭 WebRTC 音轨。这是因为当对方取消静音后,客户端发送音频与 m.call.sdp_stream_metadata_changed 事件到达之间可能略有延迟,这段音频会被错过。对方静音后将停止发送音频,无需担心无意识的音频发送。

对于 video_muted,建议仍应本地关闭视频流,避免接收端看到黑屏。

sdp_stream_metadata 存在,但来流未被列在其中,应直接忽略。若某流用途未知(purpose 类型未知)也应忽略。

为保证兼容性,若对方首次发来的 m.call.invitem.call.answer 缺少 sdp_stream_metadata 属性,客户端应假定对方不支持此属性,即无法区分多流,客户端仅应使用第一条来流,并勿发送多于一条。

实现本规范的客户端应忽略无流的轨道(streamless tracks)。

被邀请方

若通话仅面向特定用户,invitee 字段应被加入,并设置为该用户的 Matrix ID。不含 invitee 字段的邀请,默认为面向房间内除发送者以外任何成员。

客户端在接收到未过期的邀请,invitee 字段缺失或等于本用户 Matrix ID 时,应视为有效来电,但是否响铃需根据与呼叫方关系和来电地点判定。建议客户端默认忽略来自公共房间的呼叫邀请。强烈建议即便未为来电响铃,客户端也应在房间中展示来电并标记其被忽略。

通话碰撞(Glare)

“通话碰撞”指两位用户几乎在同一时间互相呼叫对方,导致已有呼入/呼出通话而无法建立。可使用碰撞解决算法决定应挂断哪个通话,应接听哪个通话。如双方客户端实用相同算法,将会选择同一个通话,通话得以正常建立。

因通话目标为房间而非具体用户,以下碰撞解决算法仅适用于同一房间的通话:

  • 若客户端在准备发送 m.call.invite 至某房间时,收到了同一房间的 m.call.invite
    • 客户端应取消本地外呼,转而自动为用户接听来电。
  • 若客户端已向某房间发送 m.call.invite 并在等待响应时收到同房间的 m.call.invite
    • 客户端应对两个通话的 call_id 按字典序比较,保留较小者,挂断较大者;如来电为较小者,客户端应代表用户接听之。

对用户而言,通话建立过程应如同直接接通,无需察觉背后切换。任何初始化媒体流应当平滑迁移至被采纳的通话。

服务器行为

Homeserver 可以(可选)向客户端提供 TURN 服务器信息,便于客户端通过 TURN 实现点对点通信。客户端可通过下述 HTTP API 获取 TURN 服务器信息。

GET /_matrix/client/v3/voip/turnServer


This API provides credentials for the client to use when initiating calls.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The TURN server credentials.
429 This request was rate-limited.

200 response

Name Type Description
password string

Required: The password to use.

ttl integer

Required: The time-to-live in seconds

uris [string]

Required: A list of TURN URIs

username string

Required: The username to use.

{
  "password": "JlKfBy1QwLrO20385QyAtEyIv0=",
  "ttl": 86400,
  "uris": [
    "turn:turn.example.com:3478?transport=udp",
    "turn:10.20.30.40:3478?transport=tcp",
    "turns:10.20.30.40:443?transport=tcp"
  ],
  "username": "1443779631:@user:example.com"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

安全性考量

通话仅应在仅有两位用户的房间发起。若在多人聊天室发起,其他用户可能会拦截并接听该通话。

输入通知

用户可能希望在有人在房间中输入时收到通知。这可以通过输入通知实现。这些属于临时事件,因此不会成为事件图的一部分。输入通知的作用范围仅限于某个房间。

事件

m.typing


Informs the client of the list of users currently typing.

Event type: Message event

Content

Name Type Description
user_ids [string]

Required: The list of user IDs typing in this room, if any.

Examples

{
  "content": {
    "user_ids": [
      "@alice:matrix.org",
      "@bob:example.com"
    ]
  },
  "type": "m.typing"
}

客户端行为

当客户端接收到 m.typing 事件时,必须使用该事件中的用户 ID 列表来替换其当前所知的正在输入的所有用户。其原因在于服务器不会记住那些当前未在输入的用户,因为该列表增长得很快。客户端应将所有未在此列表中的用户 ID 标记为未输入状态。

建议客户端存储一个表示用户是否正在输入的 boolean 值。当该值为 true 时,应每隔 N 秒定时触发一次定时器,发送一次输入状态的 HTTP 请求。N 推荐值为 20-30 秒以内。客户端应不断重新发送此请求,以持续告知服务器用户仍在输入中。由于后续请求会取代旧的请求,建议在预期超时前留有 5 秒的安全余量。当用户停止输入时,将 boolean 状态变为 false 的变化应触发另一次 HTTP 请求,以告知服务器用户已停止输入。

PUT /_matrix/client/v3/rooms/{roomId}/typing/{userId}


This tells the server that the user is typing for the next N milliseconds where N is the value specified in the timeout key. Alternatively, if typing is false, it tells the server that the user has stopped typing.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room in which the user is typing.

userId string

Required: The user who has started to type.

Request body

Name Type Description
timeout integer

The length of time in milliseconds to mark this user as typing.

typing boolean

Required: Whether the user is typing or not. If false, the timeout key can be omitted.

Request body example

{
  "timeout": 30000,
  "typing": true
}

Responses

Status Description
200 The new typing state was set.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

安全性注意事项

客户端可能不希望通知房间内的所有人他们正在输入,而只通知房间内特定的用户。

回执

[Changed in v1.4] 新增了私有已读回执。

本模块增加了对回执的支持。回执是一种对事件的确认方式。该模块定义了用于表示用户已读至某一事件的 m.read 回执,以及用于相同目的但不会被其他用户察觉的 m.read.private 回执。主要来说,m.read.private 旨在清除通知,而不向他人公开已读状态。

为每个事件发送回执可能导致向主服务器发送大量流量。为了防止这一问题,回执采用“已读至”标记的方式实现。此标记表示确认适用于“至(含)”指定事件的所有事件。例如,将某事件标记为“已读”就意味着用户已经阅读了至此的所有事件。关于已读回执如何影响通知计数,请参见接收通知章节。

[Added in v1.4] 已读回执主要有三种形式:

  • 非线程化:表示已读至某事件的回执,与线程无关。这等同于线程功能引入前的已读回执。
  • 线程化,主时间线:表示对非特定线程事件的已读回执。用线程 ID main 标识。
  • 线程化,特定线程:表示在指定线程内的已读回执。用线程根事件的事件 ID 标识。

有关线程化回执的更多详细信息,请参阅下文

事件

[Changed in v1.4] 每个 user_idreceipt_type 和类别(非线程化,或 thread_id)三元组必须只关联一个 event_id

m.receipt


Changed in v1.4: Added m.read.private receipts to the event’s content.

Informs the client of new receipts.

Event type: Message event

Content

Type Description
{Event ID: Event Receipts}

The mapping of event ID to a collection of receipts for this event ID. The event ID is the ID of the event being acknowledged and not an ID for the receipt itself.

Event Receipts
Name Type Description
m.read {User ID: Receipt}

A collection of users who have sent m.read receipts for this event. The string key is the user ID the receipt belongs to.

m.read.private {User ID: Receipt}

Similar to m.read, the users who have sent m.read.private receipts for this event. Due to the nature of private read receipts, this should only ever have the current user’s ID.

Receipt
Name Type Description
thread_id string

The root thread event’s ID (or main) for which thread this receipt is intended to be under. If not specified, the read receipt is unthreaded (default).

Added in v1.4

ts integer

The timestamp the receipt was sent at.

Examples

{
  "content": {
    "$1435641916114394fHBLK:matrix.org": {
      "m.read": {
        "@erikj:jki.re": {
          "ts": 1436451550453
        }
      },
      "m.read.private": {
        "@self:example.org": {
          "ts": 1661384801651
        }
      }
    }
  },
  "type": "m.receipt"
}

客户端行为

[Changed in v1.4] 修订以支持线程化已读回执。

/sync 接口中,回执列在指定房间的 ephemeral 事件数组下。新收到的回执是增量信息,用于更新已有的映射。客户端应依据 user_idreceipt_type 和(如有)thread_id 替换旧的已读回执。例如:

客户端收到 m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $aaa:example.com
  thread_id = undefined

客户端收到另一个 m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $bbb:example.com
  thread_id = main

此时客户端尚未替换任何确认。

客户端再次收到 m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $ccc:example.com
  thread_id = undefined

客户端用新回执 $ccc:example.com 替换之前 $aaa:example.com 的确认,但不会替换 $bbb:example.com,因为它属于线程。

客户端再次收到 m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $ddd:example.com
  thread_id = main

现在客户端用新 $ddd:example.com 的确认替换旧的 $bbb:example.com。客户端不会替换 $ccc:example.com 的旧回执,因为它是未线程化的。

客户端应在确定事件已显示给用户时才发送已读回执。仅仅收到事件并不能确保用户已经看到。用户应当执行某些操作,如查看事件所处房间或关闭通知,事件方可计为“已读”。客户端不应为自己的用户发送已读回执。

与发送回执的规则类似,线程化回执应出现在线程上下文中。如果线程被折叠,客户端尚未向用户展示该事件(或任何相关已读回执)。一旦用户展开线程,就应发送线程化已读回执,并显示来自其他用户的每线程回执。

客户端可通过以下 HTTP API 与其用户相关的回执状态进行更新。

POST /_matrix/client/v3/rooms/{roomId}/receipt/{receiptType}/{eventId}


This API updates the marker for the given receipt type to the event ID specified.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The event ID to acknowledge up to.

receiptType string

Required: The type of receipt to send. This can also be m.fully_read as an alternative to /read_markers.

Note that m.fully_read does not appear under m.receipt: this endpoint effectively calls /read_markers internally when presented with a receipt type of m.fully_read.

One of: [m.read, m.read.private, m.fully_read].

Changed in v1.4: Allow m.read.private receipts and m.fully_read markers to be set.

roomId string

Required: The room in which to send the event.

Request body

Name Type Description
thread_id string

The root thread event’s ID (or main) for which thread this receipt is intended to be under. If not specified, the read receipt is unthreaded (default).

Added in v1.4

Request body example

{
  "thread_id": "main"
}

Responses

Status Description
200 The receipt was sent.
400

The thread_id is invalid in some way. For example:

  • It is not a string.
  • It is empty.
  • It is provided for an incompatible receipt type.
  • The event_id is not related to the thread_id.
429 This request was rate-limited.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "thread_id field must be a non-empty string"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
私有已读回执

[Added in v1.4]

部分用户希望标记房间为已读,以清除其通知计数,但又不希望暴露自己已经阅读了特定消息。为此,客户端可以发送 m.read.private 回执,作用同 m.read,但不会向其他用户广播回执,从而实现只清除通知不公开已读状态。

服务器不得m.read.private 回执发送给除最初发送用户外的任何其他用户。

m.readm.read.private 两者间,决定最高已读至标记时会采用“更靠前”或“更近期”的回执。关于这对通知计数影响的更多信息,请参见通知章节。

如果客户端发送的 m.read 回执“落后”于 m.read.private 回执,其他用户会看到该变化,但发送用户的通知计数不会回退到那一时间点。尽管不常见,出现 m.read(公开)回执比 m.read.private 回执滞后几条消息的情况也是合法的。

线程化已读回执

[Added in v1.4]

如果客户端未使用线程功能,则只会发送“非线程化”已读回执,无论线程如何都影响整个房间。

线程化回执指的是带有 thread_id 的回执,其目标为线程根事件的事件 ID 或主时间线用 main

线程化引入了在同一房间中进行多次独立会话的概念,因此也对应有独立的已读回执和通知计数。某事件被认为“属于线程”,需满足以下任一条件:

  • rel_typem.thread,或
  • 在事件关系链上,其父事件通过 rel_typem.thread 的方式被关联到线程根。实现时不应无限级递归,建议最多递归 3 级以覆盖间接关系。

房间内未归属于某线程的事件视为主时间线中的事件。当用作线程引用(如回执和通知计数中),主时间线采用特殊线程 ID main

线程根本身被视作主时间线事件,通过非线程关系与线程根相关的事件也被视为主时间线事件。

以下是一个房间的 DAG 示例,虚线表示事件间关系,实线表示拓扑排序。

呈现包含线程关系的单一时间线的DAG图

该 DAG 可分解为 3 条线程化时间线,其中 AB 为线程根:

呈现包含3条相关线程化时间线的 DAG 图

据此可说明:

  • I 上的线程化已读回执会标记 ABI 为已读。
  • E 上的线程化已读回执会标记 CE 为已读。
  • D 上的非线程化已读回执会标记 ABCD 为已读。

注意,仅用线程化回执将 A 标记为已读,并不会让 CEGH 也被标记为已读。线程 A 的时间线需在 H 上设置属于该线程的线程化回执才能做到。

上述 3 个例子的回执示例如下:

{
  "$I": {
    "m.read": {
      "@user:example.org": {
        "ts": 1661384801651,
        "thread_id": "main" // 因为 `I` 不在任何线程中,但回执为线程化回执
      }
    }
  },
  "$E": {
    "m.read": {
      "@user:example.org": {
        "ts": 1661384801651,
        "thread_id": "$A" // 因为 `E` 属于线程 `A`
      }
    }
  },
  "$D": {
    "m.read": {
      "@user:example.org": {
        "ts": 1661384801651
        // 无 `thread_id`,因为这是*非线程化*回执
      }
    }
  }
}

发送已读回执的条件在线程化与非线程化场景下适用方式一致。例如,当用户展开某线程时,客户端可能会为该线程事件发送私有已读回执。

服务器行为

出于高效性考虑,应将回执合并打包为按房间和线程分组的事件后再发送给客户端。

部分回执会作为类型为 m.receipt 的 EDU 跨联邦发送。该 EDU 格式为:

{
    <room_id>: {
        <receipt_type>: {
            <user_id>: { <内容(ts & thread_id, 当前支持)> }
        },
        ...
    },
    ...
}

这些均以增量方式相较此前已发送的回执推送。目前仅应使用一个 <receipt_type>m.readm.read.private 不得出现在联邦 m.receipt EDU 内。

安全性注意事项

回执是在事件图之外发送的,因此 m.receipt 事件内容不会进行完整性校验。

已读与未读标记

完全已读标记

某个房间的消息历史可以被划分为三个部分:用户已读(或表示对其不感兴趣)的消息、用户可能只读了一部分的消息,以及用户尚未见过的消息。“完全已读标记”(也称为“已读标记”)标记了第一部分的最后一个事件,而用户的已读回执则标记了第二部分的最后一个事件。

事件

用户的完全已读标记作为房间账户数据中的一个事件进行保存。可以通过读取该事件来判断用户当前的完全已读标记在房间中的位置,并且和其他账户数据事件一样,该事件在更新时将通过事件流推送下发。

完全已读标记以 m.fully_read 事件的形式保存。如果该事件在用户账户数据中不存在,应将完全已读标记视为用户的已读回执位置。

m.fully_read


The current location of the user’s read marker in a room. This event appears in the user’s room account data for the room the marker is applicable for.

Event type: Message event

Content

Name Type Description
event_id string

Required: The event the user’s read marker is located at in the room.

Examples

{
  "content": {
    "event_id": "$someplace:example.org"
  },
  "type": "m.fully_read"
}
客户端行为

客户端无法通过直接修改 m.fully_read 账户数据事件来更新完全已读标记。相反,客户端必须使用已读标记 API 来更改该值。

[Changed in v1.4] 现在可以通过 /read_markers 发送 m.read.private 回执。

已读标记 API 还可以在设置完全已读标记位置的同时,更新用户的已读回执(m.readm.read.private)的位置。因为已读回执和已读标记通常会被同时更新,因此客户端可能希望节省一次额外的 HTTP 调用。提供 m.read 和/或 m.read.private 的效果与对 /receipt/{receiptType}/{eventId} 的请求相同。

POST /_matrix/client/v3/rooms/{roomId}/read_markers


Sets the position of the read marker for a given room, and optionally the read receipt’s location.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room ID to set the read marker in for the user.

Request body

Name Type Description
m.fully_read string

The event ID the read marker should be located at. The event MUST belong to the room.

Changed in v1.4: This property is no longer required.

m.read string

The event ID to set the read receipt location at. This is equivalent to calling /receipt/m.read/$elsewhere:example.org and is provided here to save that extra call.

m.read.private string

The event ID to set the private read receipt location at. This equivalent to calling /receipt/m.read.private/$elsewhere:example.org and is provided here to save that extra call.

Added in v1.4

Request body example

{
  "m.fully_read": "$somewhere:example.org",
  "m.read": "$elsewhere:example.org",
  "m.read.private": "$elsewhere:example.org"
}

Responses

Status Description
200 The read marker, and read receipt(s) if provided, have been updated.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
服务器行为

服务器必须阻止客户端在房间账户数据中直接设置 m.fully_read。此外,服务器必须确保其对 /read_markers 请求中存在的 m.readm.read.private 的处理方式与对 /receipt/{receiptType}/{eventId} 的请求完全相同。

当由于 /read_markers 请求导致 m.fully_read 事件被更新时,服务器必须通过事件流(例如 /sync),并在满足任何适用过滤器的前提下,将更新后的账户数据事件发送到客户端。

未读标记

[Added in v1.12]

客户端可以使用“未读标记”允许用户独立于已读回执完全已读标记对房间进行后续关注的标记。

事件

用户在某房间中的未读标记通过房间账户数据中的 m.marked_unread 事件进行保存。可通过该事件来确定用户在房间中的当前未读标记状态。和其他账户数据事件一样,该事件在更新时会通过事件流下发。

m.marked_unread


The current state of the user’s unread marker in a room. This event appears in the user’s room account data for the room the marker is applicable for.

Event type: Message event

Content

Name Type Description
unread boolean

Required: Whether the room is marked unread or not.

Examples

{
  "content": {
    "unread": true
  },
  "type": "m.marked_unread"
}
客户端行为

客户端必须通过直接修改 m.marked_unread 房间账户数据事件来更新未读标记。当标记房间为未读时,客户端不应更改 m.fully_read 标记,以便保留用户在该房间的已读位置。

unread 字段为 true 时,客户端应以视觉方式标注房间为未读。具体如何实现为实现细节。推荐客户端使用与未读通知房间相似的表现方式。

当打开某房间以展示其时间线时,客户端应通过将 unread 设为 false 来重置未读标记。

如果客户端提供通过为最新事件发送已读回执将房间标记为“已读”的功能,应同时重置未读标记。

如果 m.marked_unread 事件在用户账户数据中不存在,客户端必须视为 unreadfalse 进行处理。

服务器行为

此子模块对服务器没有额外要求。

在线状态

每个用户都有在线状态信息的概念。该信息包含以下内容:

  • 用户当前是否在线
  • 用户最近一次活跃的时间(由服务器检测)
  • 某客户端是否认为用户当前处于空闲状态
  • 关于用户当前状态的任意信息(例如“正在开会”)

这些信息既包括设备级(onlineidlelast_active),也包括用户级(status)数据,由用户的宿主服务器聚合后,通过 m.presence 事件传输。在线状态事件会发送给有房间成员关系的相关用户。

用户的在线状态通过 presence 键表示,该键枚举以下几种状态之一:

  • online :用户连接到事件流时的默认状态。
  • unavailable :此时用户不可达,例如用户处于空闲状态。
  • offline :用户未连接到事件流,或有意禁止发送其个人信息。

事件

m.presence


Informs the client of a user’s presence state change.

Event type: Message event

Content

Name Type Description
avatar_url string

The current avatar URL for this user, if any.

currently_active boolean

Whether the user is currently active

displayname string

The current display name for this user, if any.

last_active_ago number

The last time since this used performed some action, in milliseconds.

presence string

Required: The presence state for this user.

One of: [online, offline, unavailable].

status_msg string

An optional description to accompany the presence.

Examples

{
  "content": {
    "avatar_url": "mxc://localhost/wefuiwegh8742w",
    "currently_active": false,
    "last_active_ago": 2478593,
    "presence": "online",
    "status_msg": "Making cupcakes"
  },
  "sender": "@example:localhost",
  "type": "m.presence"
}

客户端行为

客户端可以通过下述 HTTP API 手动设置/获取自身的在线状态。

GET /_matrix/client/v3/presence/{userId}/status


Get the given user’s presence state.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose presence state to get.


Responses

Status Description
200 The presence state for this user.
403 You are not allowed to see this user’s presence status.
404 There is no presence state for this user. This user may not exist or isn’t exposing presence information to you.

200 response

Name Type Description
currently_active boolean

Whether the user is currently active

last_active_ago integer

The length of time in milliseconds since an action was performed by this user.

presence string

Required: This user’s presence.

One of: [online, offline, unavailable].

status_msg string|null

The state message for this user if one was set.

{
  "last_active_ago": 420845,
  "presence": "unavailable"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not allowed to see their presence"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "An unknown error occurred"
}

PUT /_matrix/client/v3/presence/{userId}/status


This API sets the given user’s presence state. When setting the status, the activity time is updated to reflect that activity; the client does not need to specify the last_active_ago field. You cannot set the presence state of another user.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user whose presence state to update.

Request body

Name Type Description
presence string

Required: The new presence state.

One of: [online, offline, unavailable].

status_msg string

The status message to attach to this state.

Request body example

{
  "presence": "online",
  "status_msg": "I am here."
}

Responses

Status Description
200 The new presence state was set.
429 This request was rate-limited.

200 response

{}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
距离上一次活跃时长

服务器会维护一次记录“最后一次检测到用户主动事件”的时间戳。主动事件可能是向房间发送消息,或将在线状态更改为 online。这个时间戳通过名为 last_active_ago 的键呈现,表示自上次主动事件以来的相对毫秒数。

为减少服务器向客户端发送的在线状态更新数量,当在线状态为 online 时,服务器可能会包含一个布尔字段 currently_active。如果该字段为 true,服务器将不会继续发送活跃时间的更新,直到向客户端发送的更新中 a) currently_active 变为 false,或 b) 状态变为非 online。在此期间,客户端应始终认为该用户处于活跃状态,而不考虑 last_active_ago 的具体值。

每当服务器向客户端推送在线状态事件时,最新的活跃时间必须是当前的。currently_active 机制仅用于服务器停止持续推送在线状态更新,而不应禁用活跃时间的追踪。因此,客户端可以通过显式请求某用户的在线状态来获取最新的活跃持续时长。

空闲超时

如果用户的最后一次活跃时间超过了设定的阈值(比如 5 分钟),服务器会自动将用户状态设置为 unavailable。客户端也可以手动将用户状态设置为 unavailable。只要用户任意一个客户端有新的活动导致活跃时间刷新,服务器会自动将其在线状态设置为 online

安全性注意事项

在线状态信息会与所有目标用户的房间成员共享。在大型公共房间中,这种共享可能并不理想。

内容库

内容库(或称“媒体库”)允许用户将文件上传到其本地通信服务器(homeserver)以供日后使用。例如,用户想要发送到房间的文件会上传至此,用户想要使用的头像也同样如此。

上传文件时,客户端会向用户本地通信服务器的特定资源发送 POST 请求,该资源会返回一个 mxc:// URI,供日后通过 GET 请求进行下载。内容的下载则是从接收方的本地通信服务器完成,如果内容不是本地的,必须先通过同样的 API 从源通信服务器转存内容(除非源通信服务器和目的通信服务器为同一台服务器)。

在提供内容服务时,服务器应当提供 Content-Security-Policy 头。推荐的安全策略为: sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';

[Added in v1.4] 当服务器向客户端提供内容时,还应当额外提供 Cross-Origin-Resource-Policy: cross-origin 头,以便(Web)客户端能够访问如 SharedArrayBuffer 等受限 API,在与媒体库进行交互时使用。

[Changed in v1.11] 未认证的下载端点已被弃用,建议使用新的、需要认证的端点。此更改包括将所有媒体端点的路径从 /_matrix/media/* 更新为 /_matrix/client/{version}/media/*,但 /upload/create 端点除外。这两个上传/创建端点预计将在之后的版本中进行类似的迁移。

Matrix 内容(mxc://)URI

内容的位置以 Matrix 内容(mxc://)URI 形式表示。格式如下:

mxc://<server-name>/<media-id>

<server-name> :内容最初上传所在的通信服务器名称,例如 matrix.org
<media-id> :用以标识内容的不透明 ID。

客户端行为

客户端可通过以下端点访问内容库。

[Changed in v1.11] / _matrix/media 层级下的多个端点已弃用并被新的、需要认证的端点取代。已弃用端点在下文中有注明。

在 Matrix 1.12 版本,服务器应当“冻结”已弃用的非认证端点,以防止新上传的媒体被下载。这意味着冻结前上传的媒体仍可通过已弃用端点访问,而冻结后(或期间)上传的媒体应当只能通过新的认证端点访问。对于远程媒体,“新上传”由缓存填充时间决定。这意味着媒体本身可能早于冻结,但因服务器需重新下载,所以被视为“新媒体”。

客户端应当在服务器冻结非认证访问之前,更新以支持已认证的端点。

服务器在冻结前应充分考虑其本地生态影响。例如,确保用户常用客户端支持新端点,或者更新桥接程序以使用媒体代理等。

此外,用于 m.login.sso 流程的 IdP 图标 应从冻结中排除。详情请参阅 m.login.sso 流程的架构说明。

服务器示例时间表如下:

  • Matrix 1.11 发行:客户端开始支持认证媒体访问。
  • Matrix 1.12 发行:服务器冻结非认证媒体访问。
    • 此前上传的媒体仍可通过弃用端点访问。
    • 新上传(或缓存)的媒体能通过认证端点访问。

预计 Matrix 1.12 将于 2024 年 7~9 月正式发布。

GET /_matrix/client/v1/media/config


Added in v1.11

This endpoint allows clients to retrieve the configuration of the content repository, such as upload limitations. Clients SHOULD use this as a guide when using content repository endpoints. All values are intentionally left optional. Clients SHOULD follow the advice given in the field description when the field is not available.

Both clients and server administrators should be aware that proxies between the client and the server may affect the apparent behaviour of content repository APIs, for example, proxies may enforce a lower upload size limit than is advertised by the server on this endpoint.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The public content repository configuration for the matrix server.
429 This request was rate-limited.

200 response

Name Type Description
m.upload.size integer

The maximum size an upload can be in bytes. Clients SHOULD use this as a guide when uploading content. If not listed or null, the size limit should be treated as unknown.

{
  "m.upload.size": 50000000
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v1/media/download/{serverName}/{mediaId}


Added in v1.11

Clients SHOULD NOT generate or use URLs which supply the access token in the query string. These URLs may be copied by users verbatim and provided in a chat message to another user, disclosing the sender’s access token.

Clients MAY be redirected using the 307/308 responses below to download the request object. This is typical when the homeserver uses a Content Delivery Network (CDN).

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
mediaId string

Required: The media ID from the mxc:// URI (the path component).

serverName Server Name

Required: The server name from the mxc:// URI (the authority component).

query parameters
Name Type Description
timeout_ms integer

The maximum number of milliseconds that the client is willing to wait to start receiving data, in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). The content repository SHOULD impose a maximum value for this parameter. The content repository MAY respond before the timeout.

Added in v1.7


Responses

Status Description
200 The content that was previously uploaded.
307 A redirect to the requested content.
308 A redirect to the requested content.
429 This request was rate-limited.
502 The content is too large for the server to serve.
504 The content is not yet available. A standard error response will be returned with the errcode M_NOT_YET_UPLOADED.

200 response

Headers
Name Type Description
Content-Disposition string

Required: The disposition of the returned content. MUST be one of inline or attachment, and SHOULD contain a file name.

If the Content-Type is allowed in the restrictions for serving inline content, servers SHOULD use inline, otherwise they SHOULD use attachment.

If the upload was made with a filename, this header MUST contain the same filename. Otherwise, filename is excluded from the header. If the media being downloaded is remote, the remote server’s filename in the Content-Disposition header is used as the filename instead. When the header is not supplied, or does not supply a filename, the local download response does not include a filename.

Changed in v1.12: This header became required.

Content-Type string

Required: The content type of the file that was previously uploaded.

The server MUST return a Content-Type which is either exactly the same as the original upload, or reasonably close. The bounds of “reasonable” are:

  • Adding a charset to text/* content types.
  • Detecting HTML and using text/html instead of text/plain.
  • Using application/octet-stream when the server determines the content type is obviously wrong. For example, an encrypted file being claimed as image/png.
  • Returning application/octet-stream when the media has an unknown/unprovided Content-Type. For example, being uploaded before the server tracked content types or when the remote server is non-compliantly omitting the header entirely.

Actions not in the spirit of the above are not considered “reasonable”.

Changed in v1.12: This header became required in order to support Content-Disposition, and the behaviour to compute its value was clarified.

Content-Type Description
application/octet-stream

Required. The bytes for the uploaded file.

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

502 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to serve"
}

504 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_YET_UPLOADED",
  "error": "Content has not yet been uploaded"
}

GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}


Added in v1.11

This will download content from the content repository (same as the previous endpoint) but replaces the target file name with the one provided by the caller.

Clients SHOULD NOT generate or use URLs which supply the access token in the query string. These URLs may be copied by users verbatim and provided in a chat message to another user, disclosing the sender’s access token.

Clients MAY be redirected using the 307/308 responses below to download the request object. This is typical when the homeserver uses a Content Delivery Network (CDN).

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
fileName string

Required: A filename to give in the Content-Disposition header.

mediaId string

Required: The media ID from the mxc:// URI (the path component).

serverName Server Name

Required: The server name from the mxc:// URI (the authority component).

query parameters
Name Type Description
timeout_ms integer

The maximum number of milliseconds that the client is willing to wait to start receiving data, in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). The content repository SHOULD impose a maximum value for this parameter. The content repository MAY respond before the timeout.

Added in v1.7


Responses

Status Description
200 The content that was previously uploaded.
307 A redirect to the requested content.
308 A redirect to the requested content.
429 This request was rate-limited.
502 The content is too large for the server to serve.
504 The content is not yet available. A standard error response will be returned with the errcode M_NOT_YET_UPLOADED.

200 response

Headers
Name Type Description
Content-Disposition string

Required: The disposition of the returned content. MUST be one of inline or attachment, and MUST contain the file name requested in the path.

If the Content-Type is allowed in the restrictions for serving inline content, servers SHOULD use inline, otherwise they SHOULD use attachment.

Changed in v1.12: This header became required.

Content-Type string

Required: The content type of the file that was previously uploaded.

The server MUST return a Content-Type which is either exactly the same as the original upload, or reasonably close. The bounds of “reasonable” are:

  • Adding a charset to text/* content types.
  • Detecting HTML and using text/html instead of text/plain.
  • Using application/octet-stream when the server determines the content type is obviously wrong. For example, an encrypted file being claimed as image/png.
  • Returning application/octet-stream when the media has an unknown/unprovided Content-Type. For example, being uploaded before the server tracked content types or when the remote server is non-compliantly omitting the header entirely.

Actions not in the spirit of the above are not considered “reasonable”.

Changed in v1.12: This header became required in order to support Content-Disposition, and the behaviour to compute its value was clarified.

Content-Type Description
application/octet-stream

Required. The bytes for the uploaded file.

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

502 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to serve"
}

504 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_YET_UPLOADED",
  "error": "Content has not yet been uploaded"
}

GET /_matrix/client/v1/media/preview_url


Added in v1.11

Get information about a URL for the client. Typically this is called when a client sees a URL in a message and wants to render a preview for the user.

Clients should consider avoiding this endpoint for URLs posted in encrypted rooms. Encrypted rooms often contain more sensitive information the users do not want to share with the homeserver, and this can mean that the URLs being shared should also not be shared with the homeserver.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
ts integer

The preferred point in time to return a preview for. The server may return a newer version if it does not have the requested version available.

url URI

Required: The URL to get a preview of.


Responses

Status Description
200 The OpenGraph data for the URL, which may be empty. Some values are replaced with matrix equivalents if they are provided in the response. The differences from the OpenGraph protocol are described here.
429 This request was rate-limited.

200 response

Name Type Description
matrix:image:size integer

The byte-size of the image. Omitted if there is no image attached.

og:image URI

An mxc:// URI to the image. Omitted if there is no image.

{
  "matrix:image:size": 102400,
  "og:description": "This is a really cool blog post from matrix.org",
  "og:image": "mxc://example.com/ascERGshawAWawugaAcauga",
  "og:image:height": 48,
  "og:image:type": "image/png",
  "og:image:width": 48,
  "og:title": "Matrix Blog Post"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}


Added in v1.11

Download a thumbnail of content from the content repository. See the Thumbnails section for more information.

Clients SHOULD NOT generate or use URLs which supply the access token in the query string. These URLs may be copied by users verbatim and provided in a chat message to another user, disclosing the sender’s access token.

Clients MAY be redirected using the 307/308 responses below to download the request object. This is typical when the homeserver uses a Content Delivery Network (CDN).

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
mediaId string

Required: The media ID from the mxc:// URI (the path component).

serverName Server Name

Required: The server name from the mxc:// URI (the authority component).

query parameters
Name Type Description
animated boolean

Indicates preference for an animated thumbnail from the server, if possible. Animated thumbnails typically use the content types image/gif, image/png (with APNG format), image/apng, and image/webp instead of the common static image/png or image/jpeg content types.

When true, the server SHOULD return an animated thumbnail if possible and supported. When false, the server MUST NOT return an animated thumbnail. For example, returning a static image/png or image/jpeg thumbnail. When not provided, the server SHOULD NOT return an animated thumbnail.

Servers SHOULD prefer to return image/webp thumbnails when supporting animation.

When true and the media cannot be animated, such as in the case of a JPEG or PDF, the server SHOULD behave as though animated is false.

Added in v1.11

height integer

Required: The desired height of the thumbnail. The actual thumbnail may be larger than the size specified.

method string

The desired resizing method. See the Thumbnails section for more information.

One of: [crop, scale].

timeout_ms integer

The maximum number of milliseconds that the client is willing to wait to start receiving data, in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). The content repository SHOULD impose a maximum value for this parameter. The content repository MAY respond before the timeout.

Added in v1.7

width integer

Required: The desired width of the thumbnail. The actual thumbnail may be larger than the size specified.


Responses

Status Description
200 A thumbnail of the requested content.
307 A redirect to the thumbnail of the requested content.
308 A redirect to the thumbnail of the requested content.
400 The request does not make sense to the server, or the server cannot thumbnail the content. For example, the client requested non-integer dimensions or asked for negatively-sized images.
413 The local content is too large for the server to thumbnail.
429 This request was rate-limited.
502 The remote content is too large for the server to thumbnail.
504 The content is not yet available. A standard error response will be returned with the errcode M_NOT_YET_UPLOADED.

200 response

Headers
Name Type Description
Content-Disposition string

Required: The disposition of the returned content. MUST be inline, and SHOULD contain a file name (e.g. thumbnail.png).

Servers should note the Content-Type restrictions for serving inline content, as these limitations imply which formats should be used for thumbnail generation.

Added in v1.12

Content-Type string

Required: The content type of the thumbnail.

One of: [image/jpeg, image/png, image/apng, image/gif, image/webp].

Changed in v1.12: This header became required in order to support Content-Disposition.

Content-Type Description
image/apng

Required. The bytes for the animated thumbnail.

Added in v1.11

image/gif

Required. The bytes for the animated thumbnail.

Added in v1.11

image/jpeg

Required. The bytes for the thumbnail.

image/png

Required. The bytes for the thumbnail. The thumbnail MAY use an animated format if animated=true.

Changed in v1.11: The PNG may be of the APNG variety if animation is supported and requested.

image/webp

Required. The bytes for the animated thumbnail.

Added in v1.11

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "Cannot generate thumbnails for the requested content"
}

413 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to thumbnail"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

502 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to thumbnail"
}

504 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_YET_UPLOADED",
  "error": "Content has not yet been uploaded"
}

POST /_matrix/media/v1/create


Added in v1.7

Creates a new mxc:// URI, independently of the content being uploaded. The content must be provided later via PUT /_matrix/media/v3/upload/{serverName}/{mediaId}.

The server may optionally enforce a maximum age for unused IDs, and delete media IDs when the client doesn’t start the upload in time, or when the upload was interrupted and not resumed in time. The server should include the maximum POSIX millisecond timestamp to complete the upload in the unused_expires_at field in the response JSON. The recommended default expiration is 24 hours which should be enough time to accommodate users on poor connection who find a better connection to complete the upload.

As well as limiting the rate of requests to create mxc:// URIs, the server should limit the number of concurrent pending media uploads a given user can have. A pending media upload is a created mxc:// URI where (a) the media has not yet been uploaded, and (b) has not yet expired (the unused_expires_at timestamp has not yet passed). In both cases, the server should respond with an HTTP 429 error with an errcode of M_LIMIT_EXCEEDED.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The mxc:// URI for the uploaded content.
403 The user does not have permission to upload the content.
429 This request was rate-limited.

200 response

Name Type Description
content_uri Matrix Content URI

Required: The mxc:// URI at which the content will be available, once it is uploaded.

unused_expires_at integer

The timestamp (in milliseconds since the unix epoch) when the generated media id will expire, if media is not uploaded.

{
  "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw",
  "unused_expires_at": 1647257217083
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot upload this content"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/media/v3/config


This API is deprecated and will be removed from a future release.

This endpoint allows clients to retrieve the configuration of the content repository, such as upload limitations. Clients SHOULD use this as a guide when using content repository endpoints. All values are intentionally left optional. Clients SHOULD follow the advice given in the field description when the field is not available.

NOTE: Both clients and server administrators should be aware that proxies between the client and the server may affect the apparent behaviour of content repository APIs, for example, proxies may enforce a lower upload size limit than is advertised by the server on this endpoint.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The public content repository configuration for the matrix server.
429 This request was rate-limited.

200 response

Name Type Description
m.upload.size integer

The maximum size an upload can be in bytes. Clients SHOULD use this as a guide when uploading content. If not listed or null, the size limit should be treated as unknown.

{
  "m.upload.size": 50000000
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/media/v3/download/{serverName}/{mediaId}


This API is deprecated and will be removed from a future release.

Replaced by GET /_matrix/client/v1/media/download/{serverName}/{mediaId} (requires authentication).

[Changed in v1.11] This endpoint MAY return 404 M_NOT_FOUND for media which exists, but is after the server froze unauthenticated media access. See Client Behaviour for more information.

Rate-limited: Yes
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
mediaId string

Required: The media ID from the mxc:// URI (the path component).

serverName Server Name

Required: The server name from the mxc:// URI (the authority component).

query parameters
Name Type Description
allow_redirect boolean

Indicates to the server that it may return a 307 or 308 redirect response that points at the relevant media content. When not explicitly set to true the server must return the media content itself.

Added in v1.7

allow_remote boolean

Indicates to the server that it should not attempt to fetch the media if it is deemed remote. This is to prevent routing loops where the server contacts itself.

Defaults to true if not provided.

timeout_ms integer

The maximum number of milliseconds that the client is willing to wait to start receiving data, in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). The content repository SHOULD impose a maximum value for this parameter. The content repository MAY respond before the timeout.

Added in v1.7


Responses

Status Description
200 The content that was previously uploaded.
307 A redirect to the requested content.
308 A redirect to the requested content.
429 This request was rate-limited.
502 The content is too large for the server to serve.
504 The content is not yet available. A standard error response will be returned with the errcode M_NOT_YET_UPLOADED.

200 response

Headers
Name Type Description
Content-Disposition string

Required: The disposition of the returned content. MUST be one of inline or attachment, and SHOULD contain a file name.

If the Content-Type is allowed in the restrictions for serving inline content, servers SHOULD use inline, otherwise they SHOULD use attachment.

If the upload was made with a filename, this header MUST contain the same filename. Otherwise, filename is excluded from the header. If the media being downloaded is remote, the remote server’s filename in the Content-Disposition header is used as the filename instead. When the header is not supplied, or does not supply a filename, the local download response does not include a filename.

Changed in v1.12: This header became required.

Content-Type string

Required: The content type of the file that was previously uploaded.

The server MUST return a Content-Type which is either exactly the same as the original upload, or reasonably close. The bounds of “reasonable” are:

  • Adding a charset to text/* content types.
  • Detecting HTML and using text/html instead of text/plain.
  • Using application/octet-stream when the server determines the content type is obviously wrong. For example, an encrypted file being claimed as image/png.
  • Returning application/octet-stream when the media has an unknown/unprovided Content-Type. For example, being uploaded before the server tracked content types or when the remote server is non-compliantly omitting the header entirely.

Actions not in the spirit of the above are not considered “reasonable”.

Changed in v1.12: This header became required in order to support Content-Disposition, and the behaviour to compute its value was clarified.

Content-Type Description
application/octet-stream

Required. The bytes for the uploaded file.

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

502 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to serve"
}

504 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_YET_UPLOADED",
  "error": "Content has not yet been uploaded"
}

GET /_matrix/media/v3/download/{serverName}/{mediaId}/{fileName}


This API is deprecated and will be removed from a future release.

This will download content from the content repository (same as the previous endpoint) but replace the target file name with the one provided by the caller.

[Changed in v1.11] This endpoint MAY return 404 M_NOT_FOUND for media which exists, but is after the server froze unauthenticated media access. See Client Behaviour for more information.

Rate-limited: Yes
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
fileName string

Required: A filename to give in the Content-Disposition header.

mediaId string

Required: The media ID from the mxc:// URI (the path component).

serverName Server Name

Required: The server name from the mxc:// URI (the authority component).

query parameters
Name Type Description
allow_redirect boolean

Indicates to the server that it may return a 307 or 308 redirect response that points at the relevant media content. When not explicitly set to true the server must return the media content itself.

Added in v1.7

allow_remote boolean

Indicates to the server that it should not attempt to fetch the media if it is deemed remote. This is to prevent routing loops where the server contacts itself.

Defaults to true if not provided.

timeout_ms integer

The maximum number of milliseconds that the client is willing to wait to start receiving data, in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). The content repository SHOULD impose a maximum value for this parameter. The content repository MAY respond before the timeout.

Added in v1.7


Responses

Status Description
200 The content that was previously uploaded.
307 A redirect to the requested content.
308 A redirect to the requested content.
429 This request was rate-limited.
502 The content is too large for the server to serve.
504 The content is not yet available. A standard error response will be returned with the errcode M_NOT_YET_UPLOADED.

200 response

Headers
Name Type Description
Content-Disposition string

Required: The disposition of the returned content. MUST be one of inline or attachment, and MUST contain the file name requested in the path.

If the Content-Type is allowed in the restrictions for serving inline content, servers SHOULD use inline, otherwise they SHOULD use attachment.

Changed in v1.12: This header became required.

Content-Type string

Required: The content type of the file that was previously uploaded.

The server MUST return a Content-Type which is either exactly the same as the original upload, or reasonably close. The bounds of “reasonable” are:

  • Adding a charset to text/* content types.
  • Detecting HTML and using text/html instead of text/plain.
  • Using application/octet-stream when the server determines the content type is obviously wrong. For example, an encrypted file being claimed as image/png.
  • Returning application/octet-stream when the media has an unknown/unprovided Content-Type. For example, being uploaded before the server tracked content types or when the remote server is non-compliantly omitting the header entirely.

Actions not in the spirit of the above are not considered “reasonable”.

Changed in v1.12: This header became required in order to support Content-Disposition, and the behaviour to compute its value was clarified.

Content-Type Description
application/octet-stream

Required. The bytes for the uploaded file.

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

502 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to serve"
}

504 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_YET_UPLOADED",
  "error": "Content has not yet been uploaded"
}

GET /_matrix/media/v3/preview_url


This API is deprecated and will be removed from a future release.

Get information about a URL for the client. Typically this is called when a client sees a URL in a message and wants to render a preview for the user.

Note: Clients should consider avoiding this endpoint for URLs posted in encrypted rooms. Encrypted rooms often contain more sensitive information the users do not want to share with the homeserver, and this can mean that the URLs being shared should also not be shared with the homeserver.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
ts integer

The preferred point in time to return a preview for. The server may return a newer version if it does not have the requested version available.

url URI

Required: The URL to get a preview of.


Responses

Status Description
200 The OpenGraph data for the URL, which may be empty. Some values are replaced with matrix equivalents if they are provided in the response. The differences from the OpenGraph protocol are described here.
429 This request was rate-limited.

200 response

Name Type Description
matrix:image:size integer

The byte-size of the image. Omitted if there is no image attached.

og:image URI

An mxc:// URI to the image. Omitted if there is no image.

{
  "matrix:image:size": 102400,
  "og:description": "This is a really cool blog post from matrix.org",
  "og:image": "mxc://example.com/ascERGshawAWawugaAcauga",
  "og:image:height": 48,
  "og:image:type": "image/png",
  "og:image:width": 48,
  "og:title": "Matrix Blog Post"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/media/v3/thumbnail/{serverName}/{mediaId}


This API is deprecated and will be removed from a future release.

Replaced by GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId} (requires authentication).

Download a thumbnail of content from the content repository. See the Thumbnails section for more information.

[Changed in v1.11] This endpoint MAY return 404 M_NOT_FOUND for media which exists, but is after the server froze unauthenticated media access. See Client Behaviour for more information.

Rate-limited: Yes
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
mediaId string

Required: The media ID from the mxc:// URI (the path component).

serverName Server Name

Required: The server name from the mxc:// URI (the authority component).

query parameters
Name Type Description
allow_redirect boolean

Indicates to the server that it may return a 307 or 308 redirect response that points at the relevant media content. When not explicitly set to true the server must return the media content itself.

Added in v1.7

allow_remote boolean

Indicates to the server that it should not attempt to fetch the media if it is deemed remote. This is to prevent routing loops where the server contacts itself.

Defaults to true if not provided.

animated boolean

Indicates preference for an animated thumbnail from the server, if possible. Animated thumbnails typically use the content types image/gif, image/png (with APNG format), image/apng, and image/webp instead of the common static image/png or image/jpeg content types.

When true, the server SHOULD return an animated thumbnail if possible and supported. When false, the server MUST NOT return an animated thumbnail. For example, returning a static image/png or image/jpeg thumbnail. When not provided, the server SHOULD NOT return an animated thumbnail.

Servers SHOULD prefer to return image/webp thumbnails when supporting animation.

When true and the media cannot be animated, such as in the case of a JPEG or PDF, the server SHOULD behave as though animated is false.

Added in v1.11

height integer

Required: The desired height of the thumbnail. The actual thumbnail may be larger than the size specified.

method string

The desired resizing method. See the Thumbnails section for more information.

One of: [crop, scale].

timeout_ms integer

The maximum number of milliseconds that the client is willing to wait to start receiving data, in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). The content repository SHOULD impose a maximum value for this parameter. The content repository MAY respond before the timeout.

Added in v1.7

width integer

Required: The desired width of the thumbnail. The actual thumbnail may be larger than the size specified.


Responses

Status Description
200 A thumbnail of the requested content.
307 A redirect to the thumbnail of the requested content.
308 A redirect to the thumbnail of the requested content.
400 The request does not make sense to the server, or the server cannot thumbnail the content. For example, the client requested non-integer dimensions or asked for negatively-sized images.
413 The local content is too large for the server to thumbnail.
429 This request was rate-limited.
502 The remote content is too large for the server to thumbnail.
504 The content is not yet available. A standard error response will be returned with the errcode M_NOT_YET_UPLOADED.

200 response

Headers
Name Type Description
Content-Disposition string

Required: The disposition of the returned content. MUST be inline, and SHOULD contain a file name (e.g. thumbnail.png).

Servers should note the Content-Type restrictions for serving inline content, as these limitations imply which formats should be used for thumbnail generation.

Added in v1.12

Content-Type string

Required: The content type of the thumbnail.

One of: [image/jpeg, image/png, image/apng, image/gif, image/webp].

Changed in v1.12: This header became required in order to support Content-Disposition.

Content-Type Description
image/apng

Required. The bytes for the animated thumbnail.

Added in v1.11

image/gif

Required. The bytes for the animated thumbnail.

Added in v1.11

image/jpeg

Required. The bytes for the thumbnail.

image/png

Required. The bytes for the thumbnail. The thumbnail MAY use an animated format if animated=true.

Changed in v1.11: The PNG may be of the APNG variety if animation is supported and requested.

image/webp

Required. The bytes for the animated thumbnail.

Added in v1.11

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "Cannot generate thumbnails for the requested content"
}

413 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to thumbnail"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

502 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Content is too large to thumbnail"
}

504 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_YET_UPLOADED",
  "error": "Content has not yet been uploaded"
}

POST /_matrix/media/v3/upload


Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

header parameters
Name Type Description
Content-Type string

Optional. The content type of the file being uploaded.

Clients SHOULD always supply this header.

Defaults to application/octet-stream if it is not set.

Changed in v1.12: This header became explicitly optional with a default value.

query parameters
Name Type Description
filename string

The name of the file being uploaded

Request body

Content-Type Description
application/octet-stream

The content to be uploaded.

Request body example

<bytes>

Responses

Status Description
200 The mxc:// URI for the uploaded content.
403

The user does not have permission to upload the content. Some reasons for this error include:

  • The server does not permit the file type.
  • The user has reached a quota for uploaded content.
413 The uploaded content is too large for the server.
429 This request was rate-limited.

200 response

Name Type Description
content_uri Matrix Content URI

Required: The mxc:// URI to the uploaded content.

{
  "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot upload this content"
}

413 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Cannot upload files larger than 100mb"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

PUT /_matrix/media/v3/upload/{serverName}/{mediaId}


Added in v1.7

This endpoint permits uploading content to an mxc:// URI that was created earlier via POST /_matrix/media/v1/create.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

header parameters
Name Type Description
Content-Type string

Optional. The content type of the file being uploaded.

Clients SHOULD always supply this header.

Defaults to application/octet-stream if it is not set.

Changed in v1.12: This header became explicitly optional with a default value.

path parameters
Name Type Description
mediaId string

Required: The media ID from the mxc:// URI returned by POST /_matrix/media/v1/create (the path component).

serverName Server Name

Required: The server name from the mxc:// URI returned by POST /_matrix/media/v1/create (the authority component).

query parameters
Name Type Description
filename string

The name of the file being uploaded

Request body

Content-Type Description
application/octet-stream

The content to be uploaded.

Request body example

<bytes>

Responses

Status Description
200 The upload was successful.
403

The user does not have permission to upload the content. Some reasons for this error include:

  • The server does not permit the file type.
  • The user has reached a quota for uploaded content.
  • The request comes from a different user than the one that called POST /_matrix/media/v1/create.

A standard error response will be returned with the errcode M_FORBIDDEN.

404

The user has provided an invalid MXC ID. Some reasons for this error include:

A standard error response will be returned with the errcode M_NOT_FOUND.

409 The endpoint was called with a media ID that already has content. A standard error response will be returned with the errcode M_CANNOT_OVERWRITE_MEDIA.
413 The uploaded content is too large for the server.
429 This request was rate-limited.

200 response

{}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot upload this content"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown media ID"
}

409 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_CANNOT_OVERWRITE_MEDIA",
  "error": "Media already uploaded"
}

413 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_TOO_LARGE",
  "error": "Cannot upload files larger than 100mb"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
缩略图

通信服务器应能够为上传的图片和视频生成缩略图。当前尚未规定支持生成缩略图的确切文件类型,详见 Issue #1938

缩略图方法分为“裁剪(crop)”和“缩放(scale)”。“scale”方法会返回宽度或高度小于请求尺寸的图片。客户端若需适配特定矩形尺寸,则需进一步缩放和留白补齐。“crop”方法则尽量返回与请求尺寸相近、并且保持请求尺寸宽高比的图片。客户端如需适配,也应进一步缩放图片以适配目标矩形。

传给缩略图 API 的尺寸为客户端期望的最小尺寸。服务器不得返回比客户端请求尺寸更小的缩略图,除非原始内容本身尺寸就小于请求尺寸。若原始内容尺寸较小,服务器应直接返回原始内容,而非额外生成缩略图。

服务器应生成以下尺寸、方法的缩略图:

  • 32x32,裁剪
  • 96x96,裁剪
  • 320x240,缩放
  • 640x480,缩放
  • 800x600,缩放

简要总结:

  • “缩放”会保持原始图片的宽高比
  • “裁剪”会输出与请求尺寸宽高比一致的图片
  • 服务器会尽量返回尺寸大于等于请求值的图片

服务器在任何情况下都不得对缩略图进行放大。除非原始内容尺寸不足,否则服务器也不得返回小于请求尺寸的缩略图。

安全性考量

HTTP GET 端点无需认证。只要知道内容的 URL,无论实体是否在房间内都可获取内容。

mxc:// URI 易遭目录遍历攻击,如 mxc://127.0.0.1/../../../some_service/etc/passwd。这可能导致目标通信服务器试图访问并返回该文件。因此,通信服务器必须对 mxc:// URI 做合法性检查,仅允许在 server-namemedia-id 中出现字母(A-Za-z)、数字(0-9)、下划线 _ 和短横线 -。该白名单字符集兼容 RFC 4648 规范的 URL 安全 base64 编码。采用白名单优于黑名单(如黑名单排除 . 和 /),因为黑名单可能被漏洞(如百分号编码、UTF-8 编码遍历等)绕过。

通信服务器的内容服务还有额外的内容安全注意事项:

  • 客户端可能上传超大型文件。通信服务器应拒绝保存过大的文件,并返回 HTTP 413 且错误码为 M_TOO_LARGE
  • 客户端可能上传超大图片。通信服务器应拒绝为超大图片生成缩略图,返回 HTTP 413 并附带 M_TOO_LARGE
  • 远程通信服务器可能托管超大文件或图片。通信服务器应拒绝中转或生成超大远程文件/图片的缩略图,返回 HTTP 502 并附带 M_TOO_LARGE
  • 客户端可能尝试上传过多文件。通信服务器应限制单个客户端上传的文件数量与总大小,超过限制时返回 HTTP 403 并附带 M_FORBIDDEN
  • 客户端可能通过通信服务器访问大量远程文件。通信服务器应限制缓存的远程媒体的数量与总大小。
  • 客户端或远程通信服务器可能上传包含针对通信服务器缩略图机制或客户端解码器漏洞的恶意文件。
内联内容服务

若客户端配置不安全,在以 Content-Disposition: inline 方式分发媒体时,可能会受到跨站脚本攻击。为降低大部分风险,客户端应避免与通信服务器的媒体端点部署在同一域名下。服务器应当在内联内容服务时,将 Content-Type 限定为以下值之一:

  • text/css
  • text/plain
  • text/csv
  • application/json
  • application/ld+json
  • image/jpeg
  • image/gif
  • image/png
  • image/apng
  • image/webp
  • image/avif
  • video/mp4
  • video/webm
  • video/ogg
  • video/quicktime
  • audio/mp4
  • audio/webm
  • audio/aac
  • audio/mpeg
  • audio/ogg
  • audio/wave
  • audio/wav
  • audio/x-wav
  • audio/x-pn-wav
  • audio/flac
  • audio/x-flac

在指定 Content-Type 时,上述类型不太可能引发跨站脚本风险,因为客户端只会按此类型渲染数据。例如上传 HTML 文件但指定类型为 image/png 时,客户端只会认为图片损坏,并不会作为 HTML 页面渲染。因此,只要 Content-Disposition 根据该类型正确计算,服务器即可信任用户定义的内容类型。

客户端不应依赖于服务器必定在 /download 接口返回 inline 而非 attachment。服务器实现可能出于安全考量将所有下载均返回 attachment,无论内容类型为何——客户端不应对此举感到意外。

设备间消息发送(Send-to-Device messaging)

本模块为客户端提供了一种交换信令消息的方式,这些消息不会作为共享通信历史的一部分被永久存储。每条消息将精确地送达每个客户端设备一次。

该 API 的主要动机是用于交换在房间有向无环图(DAG)中无意义或不希望持久保存的数据——例如,一次性身份验证令牌或密钥数据。它并不适用于会话内容,会话内容应使用常规的 /rooms/<room_id>/send API 发送,以保持 Matrix 协议的一致性。

客户端行为

要向其他设备发送消息,客户端应调用 /sendToDevice。每个事务中,每台设备只能发送一条消息,且所有消息的事件类型必须一致。请求体中的设备ID可以设置为 *,以请求将消息发送到所有已知设备。

如果有等待客户端接收的设备间消息,这些消息将通过 /sync 返回,详见对 /sync 的扩展。客户端应检查每个返回事件的 type 字段,并忽略其无法识别的事件。

服务器行为

服务器应为本地用户存储待发送消息,直到它们成功送达目标设备。当客户端使用与有待发送消息的设备相关联的访问令牌调用 /sync 时,服务器应按到达顺序在响应体中列出这些待发送消息。

当客户端再次使用第一次响应中的 next_batch 令牌调用 /sync 时,服务器应推断该响应中的所有设备间消息已成功送达,并从存储中删除它们。

如果有大量待发送的设备间消息,服务器应限制在每次 /sync 响应中发送的消息数量。建议合理的上限为 100 条消息。

如果客户端向远程域的用户发送消息,这些消息应通过联邦协议(federation)发送至远程服务器。

协议定义

PUT /_matrix/client/v3/sendToDevice/{eventType}/{txnId}


This endpoint is used to send send-to-device events to a set of client devices.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventType string

Required: The type of event to send.

txnId string

Required: The transaction ID for this event. Clients should generate an ID unique across requests with the same access token; it will be used by the server to ensure idempotency of requests.

Request body

body
Name Type Description
messages {User ID: {string: EventContent}}

Required: The messages to send. A map from user ID, to a map from device ID to message body. The device ID may also be *, meaning all known devices for the user.

Request body example

{
  "messages": {
    "@alice:example.com": {
      "TLLBEANAAG": {
        "example_content_key": "value"
      }
    }
  }
}

Responses

Status Description
200 The message was successfully sent.

200 response

{}
对 /sync 的扩展

本模块在 /sync 响应中增加了以下属性:

参数 类型 说明
to_device ToDevice 可选。关于本客户端设备的设备间消息(send-to-device)信息。

ToDevice

参数 类型 说明
events [Event] 设备间消息列表。

Event

参数 类型 说明
content EventContent 本事件的内容。此对象中的字段将根据事件类型有所不同。
sender string 发送本事件的 Matrix 用户ID。
type string 事件类型。

示例响应:

{
  "next_batch": "s72595_4483_1934",
  "rooms": {"leave": {}, "join": {}, "invite": {}},
  "to_device": {
    "events": [
      {
        "sender": "@alice:example.com",
        "type": "m.new_device",
        "content": {
          "device_id": "XYZABCDE",
          "rooms": ["!726s6s6q:example.com"]
        }
      }
    ]
  }
}

设备管理

本模块为用户提供了管理其设备的方式。

客户端行为

实现此模块的客户端应为用户提供已注册设备的列表,并允许用户更新设备的显示名称。客户端还应允许用户删除不再使用的设备。

POST /_matrix/client/v3/delete_devices


This API endpoint uses the User-Interactive Authentication API.

Deletes the given devices, and invalidates any access token associated with them.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

devices [string]

Required: The list of device IDs to delete.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "devices": [
    "QBUAZIFURK",
    "AUIECTSRND"
  ]
}

Responses

Status Description
200 The devices were successfully removed, or had been removed previously.
401 The homeserver requires additional authentication information.

200 response

{}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

GET /_matrix/client/v3/devices


Gets information about all devices for the current user.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 Device information

200 response

Name Type Description
devices [Device]

A list of all registered devices for this user.

Device
Name Type Description
device_id string

Required: Identifier of this device.

display_name string

Display name set by the user for this device. Absent if no name has been set.

last_seen_ip string

The IP address where this device was last seen. (May be a few minutes out of date, for efficiency reasons).

last_seen_ts integer

The timestamp (in milliseconds since the unix epoch) when this devices was last seen. (May be a few minutes out of date, for efficiency reasons).

{
  "devices": [
    {
      "device_id": "QBUAZIFURK",
      "display_name": "android",
      "last_seen_ip": "1.2.3.4",
      "last_seen_ts": 1474491775024
    }
  ]
}

GET /_matrix/client/v3/devices/{deviceId}


Gets information on a single device, by device id.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
deviceId string

Required: The device to retrieve.


Responses

Status Description
200 Device information
404 The current user has no device with the given ID.

200 response

Device
Name Type Description
device_id string

Required: Identifier of this device.

display_name string

Display name set by the user for this device. Absent if no name has been set.

last_seen_ip string

The IP address where this device was last seen. (May be a few minutes out of date, for efficiency reasons).

last_seen_ts integer

The timestamp (in milliseconds since the unix epoch) when this devices was last seen. (May be a few minutes out of date, for efficiency reasons).

{
  "device_id": "QBUAZIFURK",
  "display_name": "android",
  "last_seen_ip": "1.2.3.4",
  "last_seen_ts": 1474491775024
}

PUT /_matrix/client/v3/devices/{deviceId}


Updates the metadata on the given device.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
deviceId string

Required: The device to update.

Request body

Name Type Description
display_name string

The new display name for this device. If not given, the display name is unchanged.

Request body example

{
  "display_name": "My other phone"
}

Responses

Status Description
200 The device was successfully updated.
404 The current user has no device with the given ID.

200 response

{}

DELETE /_matrix/client/v3/devices/{deviceId}


This API endpoint uses the User-Interactive Authentication API.

Deletes the given device, and invalidates any access token associated with it.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
deviceId string

Required: The device to delete.

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  }
}

Responses

Status Description
200 The device was successfully removed, or had been removed previously.
401 The homeserver requires additional authentication information.

200 response

{}

401 response

Authentication response
Name Type Description
completed [string]

A list of the stages the client has completed successfully

flows [Flow information]

Required: A list of the login flows supported by the server for this API.

params {string: object}

Contains any information that the client will need to know in order to use a given type of authentication. For each login type presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here.

session string

This is a session identifier that the client must pass back to the home server, if one is provided, in subsequent attempts to authenticate in the same API call.

Flow information
Name Type Description
stages [string]

Required: The login type of each of the stages required to complete this authentication flow

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}

安全性注意事项

删除设备具有安全风险:该操作会使分配给该设备的 access_token 失效,因此攻击者可能利用这一点注销真实用户(并且每当真实用户尝试重新登录时,攻击者都可以重复进行此操作,从而阻止用户登录)。服务器在删除设备时应要求超出 access_token 的额外身份验证措施(例如,要求用户重新输入密码)。

设备的显示名称为公开可见内容。客户端应考虑提醒用户这一点。

端到端加密

Matrix 可选支持端到端加密,允许创建房间,其对话内容无法被任何参与的主服务器解密或截获。

密钥分发

Matrix 中的加密与身份验证基于公钥密码学。Matrix 协议提供了一个基础的公钥交换机制,但需要通过带外渠道在用户之间交换指纹,以建立信任网络。

概述

1)Bob 发布其设备的公钥和支持的算法。这可能包括长期身份密钥和/或一次性密钥。

      +----------+  +--------------+
      | Bob 的主服务器  |  | Bob 的设备         |
      +----------+  +--------------+
            |              |
            |<=============|
              /keys/upload

2)Alice 请求 Bob 的公用身份密钥和支持的算法。

      +----------------+  +------------+  +----------+
      | Alice 的设备        |  | Alice 的主服务器  |  | Bob 的主服务器  |
      +----------------+  +------------+  +----------+
             |                  |               |
             |=================>|==============>|
               /keys/query        <federation>

3)Alice 选择一种算法并领取所需的一次性密钥。

      +----------------+  +------------+  +----------+
      | Alice 的设备        |  | Alice 的主服务器  |  | Bob 的主服务器  |
      +----------------+  +------------+  +----------+
             |                  |               |
             |=================>|==============>|
               /keys/claim         <federation>
密钥算法

不同的密钥算法用于不同的用途。每种密钥算法通过名称标识,并有特定的表示方式。

名称 ed25519 对应于 Ed25519 签名算法。密钥为一个 32 字节的 Ed25519 公钥,使用 unpadded Base64 编码。例如:

"SogYyrkTldLz0BXP+GYWs0qaYacUI0RleEqNT8J3riQ"

名称 curve25519 对应于 Curve25519 ECDH 算法。密钥为一个 32 字节的 Curve25519 公钥,使用 unpadded Base64 编码。例如:

"JGLn/yafz74HB2AbPLYJWIVGnKAtqECOBf11yyXac2Y"

名称 signed_curve25519 也对应于 Curve25519 ECDH 算法,但该密钥经过签名,可以进行身份认证。使用此算法的密钥以包含以下属性的对象表示:

KeyObject

参数 类型 描述
key string 必选。 未填充的 Base64 编码的 32 字节 Curve25519 公钥。
signatures Signatures 必选。 密钥对象的签名。签名过程详见 Signing JSON
fallback boolean 标记此密钥是否为 备用密钥。默认为 false

示例:

{
  "key":"06UzBknVHFMwgi7AVloY7ylC+xhOhEX4PkNge14Grl8",
  "signatures": {
    "@user:example.com": {
      "ed25519:EGURVBUNJP": "YbJva03ihSj5mPk+CHMJKUKlCXCPFXjXOK6VqBnN9nA2evksQcTGn6hwQfrgRHIDDXO2le49x7jnWJHMJrJoBQ"
    }
  }
}

ed25519curve25519 密钥用于 设备密钥。此外,ed25519 密钥也用于 跨签名密钥

signed_curve25519 密钥用于 一次性及备用密钥

设备密钥

每台设备应拥有一个 Ed25519 签名密钥。此密钥应通过设备上的加密安全源生成,且其私钥部分绝不可导出。其他客户端通过该密钥作为设备指纹,并由该密钥签署设备的其他密钥。

设备通常还需要生成若干附加密钥,具体取决于使用的消息算法。

在 Olm 1.0 版本中,每台设备还需有一个 Curve25519 身份密钥。

一次性与备用密钥

除了设备密钥(属于长期密钥),某些加密算法还要求设备拥有多个一次性密钥,这些密钥仅使用一次,用后即弃。在 Olm 1.0 版本中,设备使用由设备 Ed25519 密钥签名的 signed_curve25519 一次性密钥。

设备会生成一次性密钥上传至服务器。其他用户之后会通过 claim 领取。服务器必须确保每个一次性密钥只被领取一次:主服务器在将该一次性密钥分配给其他用户后即应删除。

[Added in v1.2] 备用密钥与一次性密钥类似,但使用后不会被消耗。如果上传了备用密钥,当设备用尽一次性密钥、用户请求密钥时,服务器会返回备用密钥。备用密钥一旦被使用,应尽快用新密钥替换。

备用密钥用于在设备离线或无法上传新密钥时防止一次性密钥耗尽。但使用备用密钥建立的会话可能易受重放攻击。

设备将通过 /sync 得知尚可被领取的一次性密钥数量,以及备用密钥是否已被使用。这样设备即可保障在线期间有充足一次性密钥,并在备用密钥被用后及时更换。

密钥上传

设备通过 /keys/upload API 将身份密钥的公钥部分以签名 JSON 对象形式上传至主服务器。JSON 对象必须包含设备 Ed25519 密钥的公钥部分,且必须由该密钥签名,详见 Signing JSON

一次性密钥和备用密钥也通过 /keys/upload API 上传。如需上传新的一次性或备用密钥则再上传。备用密钥(格式为签名 JSON 对象的密钥算法)应包含名为 fallback 且值为 true 的属性。

设备必须保存他们上传的每个密钥的私钥部分。当收到使用该密钥加密的信息后,可以删除一次性密钥的私钥部分。但有可能主服务器发出的某个一次性密钥从未被用过,因此生成密钥的设备永远也不会知道可以删除该密钥。因此,设备最终可能需要保管过多私钥。若存储私钥过多,设备可以从最早的密钥开始丢弃。

客户端不应无限期保存备用密钥的私钥,以免攻击者能解密此前用该备用密钥加密的消息。

客户端最多应该只保存 2 个备用密钥的私钥:当前未用的备用密钥及其前一个。一旦客户端确信所有用旧备用密钥加密的消息都已收到(如自第一条消息后经过一小时),应删除该备用密钥。

跟踪用户的设备列表

在 Alice 向 Bob 发送加密消息之前,需要获得 Bob 每台设备及相关身份密钥的列表,以建立这些设备的加密会话。此列表可通过 /keys/query 并在 device_keys 参数中传入 Bob 用户 ID 获得。

Bob 可能会不时添加新设备,Alice 需要及时获知并在今后的加密消息中加上新的设备。最简单做法是每发一次消息都执行一次 /keys/query,但用户数和设备数可能庞大,如此会极度低效。

因此,通常每个客户端会维护一些用户(实践中通常是与之共享加密房间的用户)的设备列表。该列表必须在客户端应用程序多次启动间持久化存储(以保留设备验证数据并在 Bob 突然添加新设备时警告 Alice)。

Alice 的客户端可按以下流程维护 Bob 的设备列表:

  1. 首先设置标记,记录现在正在跟踪 Bob 的设备列表,并有单独标记表示本地 Bob 设备列表已过期。两者都必须保存在客户端重启后依然存在的存储中。
  2. /keys/query 发送请求,device_keys 参数传入 Bob 用户 ID。请求完成后,将获取到的设备列表持久化保存,并清除“已过期”标记。
  3. 正常处理 /sync 响应时,解析 device_lists 字段的 changed 属性。如果在跟踪于列出的用户之一的设备列表,则将该用户的设备列表标记为过期,并重发 /keys/query 请求。
  4. 定期将 /sync 结果中的 next_batch 字段保存持久化。如果 Alice 后续重启客户端,可通过 /keys/changes 并将记录的 next_batch 字段作为 from 参数查询在离线期间哪些用户的设备列表已变更。如果在跟踪这些用户的设备列表,则将其标记为过期。将此列表与之前已标记过期的列表并集,然后对这些用户重新执行 /keys/query

Bob 可能在 Alice 的 /keys/query 请求仍在进行时更新设备。Alice 的客户端可能会在第一次请求未结束时,在 /sync 响应的 device_lists 字段中看到 Bob 的用户 ID,并发起第二次 /keys/query 请求。这可能导致两类相关问题。

第一个问题:当第一次请求响应时,客户端会清除记录的 Bob 设备已过期标记。如果第二次请求失败或在完成前客户端关闭,可能导致 Alice 继续使用已过期的 Bob 设备列表。

第二个问题:在某些条件下,第二次请求可能早于第一次请求完成。此时第一次请求的结果会覆盖第二次的结果。

客户端必须防范上述情况。例如,可以确保每个用户至多只有一个 /keys/query 请求在运行,对于新的请求排队等待第一个完成。或立即发起新请求,但确保忽略第一次请求的结果(例如通过取消第一次请求)。

当 Bob 和 Alice 共享房间并跟踪 Alice 设备时,Alice 离开房间后新增设备,Bob 不会知晓。当他们再次共享房间时,Bob 就有一个过时的 Alice 设备列表。为了解决该问题,Bob 的主服务器会把 Alice 的用户 ID 加入 device_lists 字段的 changed 属性中,因此 Bob 会按常规流程更新 Alice 的设备列表。另外,Bob 也可通过检查 device_lists 字段的 left 属性获知双方已不再共享任何房间,并相应地将 Alice 从跟踪列表移除。

发送加密附件

当房间启用加密时,文件应在上传到主服务器前进行加密。

操作方式为,客户端生成一个只用一次的 256 位 AES 密钥并使用 AES-CTR 模式加密该文件。计数器(Counter)应为 64 位,从 0 开始,且以随机 64 位初始化向量(IV)为前缀,两者一起组成 128 位唯一计数器块。

IV 绝不可与同一密钥重复使用。这意味着如需加密同一消息中的多个文件(如图片和缩略图),绝不可共用密钥及 IV。

加密后,文件即可上传到主服务器。必须在房间事件中包含密钥和 IV 以及上传得到的 mxc://,以便接收方可以解密。由于承载这些密钥和 IV 的事件会用 Megolm 加密,服务器无法解密文件。

还必须包含密文的哈希值,以防主服务器篡改文件内容。

客户端应以加密后的 m.room.message 事件形式发送数据,msgtype 可用 m.file,或其他对应文件类型的 msgtype。密钥采用 JSON Web Key 格式,带 W3C 扩展

m.room.message 的扩展

本模块为引用文件的 m.room.message 消息类型添加了 filethumbnail_file 属性,类型为 EncryptedFile,用于替代 urlthumbnail_url 属性,如 m.filem.image 等。

EncryptedFile

参数 类型 描述
url string 必选。 文件的 URL。
key JWK 必选。 一个 JSON Web Key 对象。
iv string 必选。 AES-CTR 使用的 128 位唯一计数块,未填充 base64 编码。
hashes {string: string} 必选。 算法名称与密文哈希的映射,未填充 base64 编码。客户端应至少支持 sha256 哈希。
v string 必选。 加密附件协议版本,必须为 v2

JWK

参数 类型 描述
kty string 必选。 密钥类型,必须为 oct
key_ops [string] 必选。 密钥操作。至少包含 encryptdecrypt
alg string 必选。 算法,必须为 A256CTR
k string 必选。 密钥,以 urlsafe 未填充 base64 编码。
ext boolean 必选。 可提取性。必须为 true。此为 W3C 扩展

示例:

{
  "content": {
    "body": "something-important.jpg",
    "file": {
      "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
      "v": "v2",
      "key": {
        "alg": "A256CTR",
        "ext": true,
        "k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0",
        "key_ops": ["encrypt","decrypt"],
        "kty": "oct"
      },
      "iv": "w+sE15fzSc0AAAAAAAAAAA",
      "hashes": {
        "sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA"
      }
    },
    "info": {
      "mimetype": "image/jpeg",
      "h": 1536,
      "size": 422018,
      "thumbnail_file": {
        "hashes": {
          "sha256": "/NogKqW5bz/m8xHgFiH5haFGjCNVmUIPLzfvOhHdrxY"
        },
        "iv": "U+k7PfwLr6UAAAAAAAAAAA",
        "key": {
          "alg": "A256CTR",
          "ext": true,
          "k": "RMyd6zhlbifsACM1DXkCbioZ2u0SywGljTH8JmGcylg",
          "key_ops": ["encrypt", "decrypt"],
          "kty": "oct"
        },
        "url": "mxc://example.org/pmVJxyxGlmxHposwVSlOaEOv",
        "v": "v2"
      },
      "thumbnail_info": {
        "h": 768,
        "mimetype": "image/jpeg",
        "size": 211009,
        "w": 432
      },
      "w": 864
    },
    "msgtype": "m.image"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
      "age": 1234
  }
}

设备验证

在 Alice 向 Bob 发送加密数据、或信任从 Bob 收到的数据之前,或许想先验证自己真正与 Bob 本人通信,而非与中间人。此验证过程需要带外渠道:仅依赖 Matrix 自身无法做到完全安全验证(否则就只能信任主服务器管理员了)。

在 Matrix 中,验证流程通常是 Alice 与 Bob 线下见面或通过其他可靠方式交流,采用下文中定义的任一种互动验证方式校验 Bob 的设备。Alice 和 Bob 也可以当面逐字读出各自的未填充 base64 编码 Ed25519 公钥(如 /keys/query 返回值)。

设备验证可能有多种结论。例如:

  • Alice 可以“接受”设备,表明她确信设备属于 Bob,今后可以为该设备加密敏感内容,并确认接收到的消息确实由该设备发出。
  • Alice 可以“拒绝”设备,如果她知道或怀疑该设备非 Bob 控制(如也不信任 Bob),则不会发送敏感内容、不再信任该设备发来的消息。
  • Alice 可以跳过设备验证流程。这种情况下虽然无法确信设备属于 Bob,但也没有证据怀疑,且加密协议依然能够防止被动窃听。

一旦签名密钥通过验证,就由加密协议去验证具体消息是否真由持有该 Ed25519 私钥的设备发出,或仅允许该设备解密。Olm 协议的具体文档见 https://matrix.org/docs/olm_signing.html

密钥验证框架

人工比对 Ed25519 密钥并不友好,易出错。为降低错误概率、提升用户体验,本规范支持一些验证方式,并允许通过用户设备间互发消息辅助验证。这些方法共用一套验证协商框架。

验证消息可以发在由双方共享的房间(应为 定向消息),也可通过 to-device 消息点对点直发两个设备。两种场景下报文结构类似,细微差别详见下文。验证不同用户应用房间消息,同一用户多个设备验证则用 to-device 消息。

一个密钥验证会话以首条消息中的 ID 标识。房间消息用初始 message 的 event ID,to-device 消息用首条消息的 transaction_id 字段,其余同会话消息继承。

一般来说,验证流程如下:

  • Alice 通过发送密钥验证请求事件,向 Bob 发起验证请求。如果在房间,事件类型为 m.room.messagemsgtype: m.key.verification.request,如用 to-device 则类型为 m.key.verification.request。事件指明 Alice 客户端支持的验证方式。(注意“Alice”与“Bob”在自验证场景其实可以是同一用户)。
  • Bob 客户端弹窗提示 Bob 接受密钥验证。Bob 接受后,其客户端发送 m.key.verification.ready 事件,载明其支持的验证方式。
  • Alice 或 Bob 选择双方都支持的一个验证方式后,主设备发送 m.key.verification.start 事件,标明所选验证方式。如果双方仅有唯一通用方式,则可自动选择。
  • Alice 和 Bob 按所选验证方式完成验证,可能涉及客户端间消息交互,双方在带外渠道核对信息,或与各自设备交互。
  • Alice 和 Bob 客户端各自发送 m.key.verification.done 通知验证成功。

任一设备可随时通过发送 m.key.verification.cancel 事件取消验证,请求体里的 code 字段指明原因。

to-device 场景下,Alice 若无法确定要验证 Bob 的哪台设备或不想指定特定设备,可以向 Bob 所有设备发 m.key.verification.request,事务 ID 相同。当 Bob 某台设备接受或拒绝(发 m.key.verification.readym.key.verification.cancel)时,Alice 要向 Bob 其他设备发送 m.key.verification.cancel(若 Bob 接受则 code 为 m.accepted,拒绝则为 m.user)。假定 Alice、Bob 各有两台设备,Bob 第一台设备接受 Alice 第二台设备的请求,协议流程如下(注意,Alice 第一个设备未参与验证,消息次序 Bob、Alice 谁先发 m.key.verification.start 都可以;最终双方互发 done 通知):

    +---------------+ +---------------+                    +-------------+ +-------------+
    | AliceDevice1  | | AliceDevice2  |                    | BobDevice1  | | BobDevice2  |
    +---------------+ +---------------+                    +-------------+ +-------------+
            |                 |                                   |               |
            |                 | m.key.verification.request        |               |
            |                 |---------------------------------->|               |
            |                 |                                   |               |
            |                 | m.key.verification.request        |               |
            |                 |-------------------------------------------------->|
            |                 |                                   |               |
            |                 |          m.key.verification.ready |               |
            |                 |<----------------------------------|               |
            |                 |                                   |               |
            |                 | m.key.verification.cancel         |               |
            |                 |-------------------------------------------------->|
            |                 |                                   |               |
            |                 |          m.key.verification.start |               |
            |                 |<----------------------------------|               |
            |                 |                                   |               |
            .
            .                       (verification messages)
            .
            |                 |                                   |               |
            |                 |           m.key.verification.done |               |
            |                 |<----------------------------------|               |
            |                 |                                   |               |
            |                 | m.key.verification.done           |               |
            |                 |---------------------------------->|               |
            |                 |                                   |               |

房间消息下,Alice 只需向房间发送一次请求事件(类型为 m.room.messagemsgtype: m.key.verification.request),而非向 Bob 各设备分别发送 m.key.verification.request。一旦 Bob 某设备发出 m.key.verification.ready,其他 Bob 设备即可知有设备已接受,自动忽略该请求,无须 Alice 主动通知。

房间加密模式下,验证流程不得因加密受阻。例如:若验证消息本身用加密,务必确保收件人所有未经验证的设备都能获得解密该消息的密钥(即使通常不会给他们解密密钥)。或者,也可将验证消息设为明文(但并不推荐)。

Bob 某设备收到 Alice 的 m.key.verification.request 且所有方法都不支持时,不应直接取消请求,以免其他设备支持。应提示 Bob 无支持方式,允许其手动拒绝。

提示 Bob 接受/拒绝 Alice 请求(或“不支持”提示)应在 timestamp(to-device)或 origin_ts(房间消息)后 10 分钟,或收到消息后 2 分钟(以先到者为准)自动消失,期间若收到 m.key.verification.cancel 则自动隐藏。

Bob 若拒绝请求,客户端需发送 code 为 m.userm.key.verification.cancel,Alice 应知晓被拒绝,并若是 to-device 消息类型,还要通知 Bob 的所有设备该请求已被拒绝。

Alice/Bob 若同时发出 m.key.verification.start 且指定同一验证方式,用户 ID 字典序较大的设备消息被忽略,视为只有较小字典序一端发起。若用户 ID 相同(即自验证),则比对设备 ID。若指定验证方式不一致,则以 code: m.unexpected_message 取消。

to-device 验证也可无请求直接发 m.key.verification.start,该行为已废弃,建议新客户端不要这样做,但应能兼容老客户端。

具体验证方式可能会添加额外步骤、事件及消息字段。定义于本规范下的方法事件类型须以 m.key.verification 命名空间为前缀,其他自定义事件按 Java 包命名原则命名。

m.room.message with msgtype: m.key.verification.request


Requests a key verification in a room. When requesting a key verification using to-device messaging, an event with type m.key.verification.request should be used.

Event type: Message event

Content

Name Type Description
body string

A fallback message to alert users that their client does not support the key verification framework, and that they should use a different method to verify keys. For example, “Alice is requesting to verify keys with you. However, your client does not support this method, so you will need to use the legacy method of key verification.”

Clients that do support the key verification framework should hide the body and instead present the user with an interface to accept or reject the key verification.

format string

The format used in the formatted_body. Currently only org.matrix.custom.html is supported.

formatted_body string

The formatted version of the body. This is required if format is specified. As with the body, clients that do support the key verification framework should hide the formatted body and instead present the user with an interface to accept or reject the key verification.

from_device string

Required: The device ID which is initiating the request.

methods [string]

Required: The verification methods supported by the sender.

msgtype string

Required:

One of: [m.key.verification.request].

to string

Required: The user that the verification request is intended for. Users who are not named in this field and who did not send this event should ignore all other events that have an m.reference relationship with this event.

Examples

{
  "content": {
    "body": "Alice is requesting to verify your device, but your client does not support verification, so you may need to use a different verification method.",
    "from_device": "AliceDevice2",
    "methods": [
      "m.sas.v1"
    ],
    "msgtype": "m.key.verification.request",
    "to": "@bob:example.org"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@alice:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.key.verification.request


Requests a key verification using to-device messaging. When requesting a key verification in a room, a m.room.message should be used, with m.key.verification.request as msgtype.

Event type: Message event

Content

Name Type Description
from_device string

Required: The device ID which is initiating the request.

methods [string]

Required: The verification methods supported by the sender.

timestamp integer

Required when sent as a to-device message. The POSIX timestamp in milliseconds for when the request was made. If the request is in the future by more than 5 minutes or more than 10 minutes in the past, the message should be ignored by the receiver.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification request. Must be unique with respect to the devices involved.

Examples

{
  "content": {
    "from_device": "AliceDevice2",
    "methods": [
      "m.sas.v1"
    ],
    "timestamp": 1559598944869,
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.request"
}

m.key.verification.ready


Accepts a key verification request. Sent in response to an m.key.verification.request event.

Event type: Message event

Content

Name Type Description
from_device string

Required: The device ID which is accepting the request.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

methods [string]

Required: The verification methods supported by the sender, corresponding to the verification methods indicated in the m.key.verification.request message.

transaction_id string

Required when sent as a to-device message. The transaction ID of the verification request, as given in the m.key.verification.request message.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "from_device": "BobDevice1",
    "methods": [
      "m.sas.v1"
    ],
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.ready"
}

m.key.verification.start


Begins a key verification process. Typically sent as a to-device event. The method field determines the type of verification. The fields in the event will differ depending on the method. This definition includes fields that are in common among all variants.

Event type: Message event

Content

Name Type Description
from_device string

Required: The device ID which is initiating the process.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

method string

Required: The verification method to use.

next_method string

Optional method to use to verify the other user’s key with. Applicable when the method chosen only verifies one user’s key. This field will never be present if the method verifies keys both ways.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification process. Must be unique with respect to the devices involved. Must be the same as the transaction_id given in the m.key.verification.request if this process is originating from a request.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "from_device": "BobDevice1",
    "method": "m.sas.v1",
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.start"
}
{
  "content": {
    "from_device": "BobDevice1",
    "hashes": [
      "sha256"
    ],
    "key_agreement_protocols": [
      "curve25519"
    ],
    "message_authentication_codes": [
      "hkdf-hmac-sha256.v2",
      "hkdf-hmac-sha256"
    ],
    "method": "m.sas.v1",
    "short_authentication_string": [
      "decimal",
      "emoji"
    ],
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.start"
}

m.key.verification.done


Indicates that a verification process/request has completed successfully.

Event type: Message event

Content

Name Type Description
m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

transaction_id string

Required when sent as a to-device message. The opaque identifier for the verification process/request.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.done"
}

m.key.verification.cancel


Cancels a key verification process/request.

Event type: Message event

Content

Name Type Description
code string

Required: The error code for why the process/request was cancelled by the user. Error codes should use the Java package naming convention if not in the following list:

  • m.user: The user cancelled the verification.

  • m.timeout: The verification process timed out. Verification processes can define their own timeout parameters.

  • m.unknown_transaction: The device does not know about the given transaction ID.

  • m.unknown_method: The device does not know how to handle the requested method. This should be sent for m.key.verification.start messages and messages defined by individual verification processes.

  • m.unexpected_message: The device received an unexpected message. Typically raised when one of the parties is handling the verification out of order.

  • m.key_mismatch: The key was not verified.

  • m.user_mismatch: The expected user did not match the user verified.

  • m.invalid_message: The message received was invalid.

  • m.accepted: A m.key.verification.request was accepted by a different device. The device receiving this error can ignore the verification request.

Clients should be careful to avoid error loops. For example, if a device sends an incorrect message and the client returns m.invalid_message to which it gets an unexpected response with m.unexpected_message, the client should not respond again with m.unexpected_message to avoid the other device potentially sending another error response.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

reason string

Required: A human readable description of the code. The client should only rely on this string if it does not understand the code.

transaction_id string

Required when sent as a to-device message. The opaque identifier for the verification process/request.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "code": "m.user",
    "reason": "User rejected the key verification request",
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.cancel"
}
短认证字符串(SAS)验证

SAS 验证是一种基于上述通用框架的用户友好密钥验证流程。其高度交互化,使用户容易参与其中。

验证过程受 Phil Zimmermann 的 ZRTP 密钥协商启发。其关键在于哈希承诺(commitment):发起 Diffie-Hellman 的一方先发送自己部分的哈希,只有收到对方部分才发明文。这样,攻击者只会有一次机会破解 DH,实际上即便只校验 n 位也能保证高安全性:若认证 n 位,攻击者成功概率为 1/2ⁿ。如验证 40 位,攻击概率小于十万亿分之一,若失败,两端的短认证字符串会不一致,从而提醒用户遭遇攻击。

要支持该方式,客户端应在 m.key.verification.requestm.key.verification.readymethods 字段中声明名称 m.sas.v1

SAS 验证主要两步:

  1. 密钥协商(类似 ZRTP 协商)。
  2. 密钥认证(基于 HMAC)。

Alice 和 Bob 互验证流程如下:

  1. Alice 和 Bob 建立安全的带外连接,如线下、视频通话等。(“安全”即无可被冒充,而非完全机密。)

  2. 双方启动密钥验证流程。

  3. Alice 设备向 Bob 设备发 m.key.verification.start,确保 Bob 的设备密钥已本地存储。

  4. Bob 设备收到后,选定双方均支持的密钥协商、哈希、MAC、SAS 算法。

  5. Bob 设备确保 Alice 设备密钥也齊。

  6. Bob 设备生成临时 Curve25519 密钥对 (K_B^private, K_B^public),计算公钥哈希。

  7. Bob 回复 m.key.verification.accept,传递承诺。

  8. Alice 保存承诺哈希备用。

  9. Alice 设备生成临时 Curve25519 密钥对 (K_A^private, K_A^public), 以 m.key.verification.key 只发送公钥。

  10. Bob 回复 m.key.verification.key,含其公钥。

  11. Alice 校验 Bob 设备发来的密钥哈希与早先的承诺及 Alice 启动消息内容一致。

  12. 双方用自己的私有临时密钥与对方的公钥做 ECDH,得共享密钥。

  13. 双方用选定算法从共享密钥派生 SAS(短认证字符串)。如有多种方式,客户端应允许用户选择。

  14. 两端人工比对 SAS,手动告知设备是否一致。

  15. 若认证一致,双方各自针对下述密钥做 MAC 认证:

    • 希望对方验证的所有密钥(通常是各自设备 ed25519 密钥及主跨签名密钥)。
    • 希望对方验证密钥的 key ID 列表。

    MAC 算法见下文

  16. 双方并行发送 m.key.verification.mac,各自附上密钥及 ID 的 MAC 值。

  17. 对端收到 m.key.verification.mac 后,本地核算 MAC 进行比对,一致则设备密钥通过认证。

  18. 双方各自发送 m.key.verification.done 完成验证。

Alice/Bob 设备间协议交互如下:

    +-------------+                    +-----------+
    | AliceDevice |                    | BobDevice |
    +-------------+                    +-----------+
          |                                 |
          | m.key.verification.start        |
          |-------------------------------->|
          |                                 |
          |       m.key.verification.accept |
          |<--------------------------------|
          |                                 |
          | m.key.verification.key          |
          |-------------------------------->|
          |                                 |
          |          m.key.verification.key |
          |<--------------------------------|
          |                                 |
          | m.key.verification.mac          |
          |-------------------------------->|
          |                                 |
          |          m.key.verification.mac |
          |<--------------------------------|
          |                                 |
错误与异常处理

过程中出现错误处理如下:

  • Alice 或 Bob 任何时刻都可取消验证。须发送 m.key.verification.cancel
  • 超时。验证流程超时设为 10 分钟,事务 ID 长时间(10 分钟未收发)未用也需过期,用户应看到超时提示,同时通知对方取消。
  • 一台设备参与多次验证,接收端需取消与该设备的所有未完成尝试。
  • 若收到未知事务 ID,须给对方发送说明原因的 m.key.verification.cancel(首次收到 m.key.verification.startm.key.verification.cancel 除外)。
  • 若双方无共同密钥、哈希、HMAC 或 SAS 算法,则发錯誤 m.key.verification.cancel
  • 用户主观判定 SAS 不一致时,需发送 m.key.verification.cancel
  • 若收到意外次序的消息,应通知对方并取消。
SAS 验证专用消息

通用验证框架基础上,SAS 用到如下事件。

m.key.verification.cancel 事件无需变更,但新增以下错误码:

  • m.unknown_method:双方无法协商出共同算法。
  • m.mismatched_commitment:哈希承诺校验失败。
  • m.mismatched_sas:SAS 不一致。

m.key.verification.start with method: m.sas.v1


Begins a SAS key verification process using the m.sas.v1 method.

Event type: Message event

Content

Name Type Description
from_device string

Required: The device ID which is initiating the process.

hashes [string]

Required: The hash methods the sending device understands. Must include at least sha256.

key_agreement_protocols [string]

Required: The key agreement protocols the sending device understands. Should include at least curve25519-hkdf-sha256.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

message_authentication_codes [string]

Required: The message authentication code methods that the sending device understands. Must include at least hkdf-hmac-sha256.v2. Should also include hkdf-hmac-sha256 for compatibility with older clients, though this identifier is deprecated and will be removed in a future version of the spec.

method string

Required: The verification method to use.

One of: [m.sas.v1].

short_authentication_string [string]

Required: The SAS methods the sending device (and the sending device’s user) understands. Must include at least decimal. Optionally can include emoji.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification process. Must be unique with respect to the devices involved. Must be the same as the transaction_id given in the m.key.verification.request if this process is originating from a request.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "from_device": "BobDevice1",
    "hashes": [
      "sha256"
    ],
    "key_agreement_protocols": [
      "curve25519"
    ],
    "message_authentication_codes": [
      "hkdf-hmac-sha256.v2",
      "hkdf-hmac-sha256"
    ],
    "method": "m.sas.v1",
    "short_authentication_string": [
      "decimal",
      "emoji"
    ],
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.start"
}

m.key.verification.accept


Accepts a previously sent m.key.verification.start message.

Event type: Message event

Content

Name Type Description
commitment string

Required: The hash (encoded as unpadded base64) of the concatenation of the device’s ephemeral public key (encoded as unpadded base64) and the canonical JSON representation of the m.key.verification.start message.

hash string

Required: The hash method the device is choosing to use, out of the options in the m.key.verification.start message.

key_agreement_protocol string

Required: The key agreement protocol the device is choosing to use, out of the options in the m.key.verification.start message.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

message_authentication_code string

Required: The message authentication code method the device is choosing to use, out of the options in the m.key.verification.start message.

short_authentication_string [string]

Required: The SAS methods both devices involved in the verification process understand. Must be a subset of the options in the m.key.verification.start message.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "commitment": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg",
    "hash": "sha256",
    "key_agreement_protocol": "curve25519",
    "message_authentication_code": "hkdf-hmac-sha256.v2",
    "method": "m.sas.v1",
    "short_authentication_string": [
      "decimal",
      "emoji"
    ],
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.accept"
}

m.key.verification.key


Sends the ephemeral public key for a device to the partner device.

Event type: Message event

Content

Name Type Description
key string

Required: The device’s ephemeral public key, encoded as unpadded base64.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "key": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg",
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.key"
}

m.key.verification.mac


Sends the MAC of a device’s key to the partner device. The MAC is calculated using the method given in message_authentication_code property of the m.key.verification.accept message.

Event type: Message event

Content

Name Type Description
keys string

Required: The MAC of the comma-separated, sorted, list of key IDs given in the mac property, encoded as unpadded base64.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

mac {string: string}

Required: A map of the key ID to the MAC of the key, using the algorithm in the verification process. The MAC is encoded as unpadded base64.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

{
  "content": {
    "keys": "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA",
    "mac": {
      "ed25519:ABCDEF": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
    },
    "transaction_id": "S0meUniqueAndOpaqueString"
  },
  "type": "m.key.verification.mac"
}
MAC 计算

验证期间,会对密钥以及密钥 ID 列表生成 MAC。

采用的 MAC 算法由 m.key.verification.acceptmessage_authentication_code 字段决定。当前要求使用 hkdf-hmac-sha256.v2,实现如下:

  1. 用 HKDF(RFC5869,哈希为 SHA-256)生成 HMAC 密钥。输入为共享密钥。无盐值,info 参数为下列组合:

    • 字符串 MATRIX_KEY_VERIFICATION_MAC
    • 被 MAC 密钥所属用户的 Matrix ID
    • 发送 MAC 的设备 ID
    • 另一用户的 Matrix ID
    • 接收 MAC 的设备 ID
    • 正在使用中的 transaction_id
    • 被 MAC 密钥的 Key ID,若为密钥列表则为字符串 KEY_IDS
  2. 用上述密钥和 SHA-256 按 RFC2104 做 HMAC 得 MAC 值。

    若为密钥,则对密钥的公钥编码作 MAC,如 ed25519 算法下为未填充 base64 格式;

    若为密钥 ID 列表,则须字典序排序、以逗号分隔(无额外空格),每个格式如 {algorithm}:{keyId},如:ed25519:Cross+Signing+Key,ed25519:DEVICEID。此设计保证接收方比对 mac 字段名时即可还原全体 Key ID,无新增删漏。

  3. MAC 最后以 base64 编码,并发送于 m.key.verification.mac 事件。

曾用的 hkdf-hmac-sha256 MAC 方法的 base64 编码错误,因 libolm 最初实现缺陷。新版本 hkdf-hmac-sha256.v2 与之算法相同,但采用标准 base64 编码。hkdf-hmac-sha256 已废弃,日后将移除。若双方都支持 hkdf-hmac-sha256.v2,则绝不可使用 hkdf-hmac-sha256

SAS HKDF 计算

所有 SAS 方法均按 RFC5869 HKDF 标准实现,哈希算法取决于之前协商,输入为协商得的共享密钥,无盐:

key_agreement_protocolcurve25519-hkdf-sha256 时,info 参数为:

  • 字符串 MATRIX_KEY_VERIFICATION_SAS|
  • 启动 m.key.verification.start 消息用户 Matrix ID,后跟 |
  • 启动消息设备 ID,后跟 |
  • 该设备发出的 m.key.verification.key 公钥,未填充 base64,后跟 |
  • 接受 m.key.verification.accept 消息用户 Matrix ID,后跟 |
  • 该设备 ID,后跟 |
  • 该设备发出的 m.key.verification.key 公钥,未填充 base64,后跟 |
  • 当前用的 transaction_id

若为废弃的 curve25519,info 依次为:

  • 字符串 MATRIX_KEY_VERIFICATION_SAS
  • 启动用户 Matrix ID
  • 启动设备 ID
  • 接受用户 Matrix ID
  • 接受设备 ID
  • transaction_id

不建议新实现支持旧方法 curve25519

HKDF 能让密钥协商更安全且易于处理。

SAS 方法:decimal

HKDF 生成 5 字节,按 13 位一组转换成十进制数(范围 0~8191),各加 1000,得到 3 组认证码。

具体为:

  • 第一组:(B₀≪5|B₁≫3)+1000
  • 第二组:( (B₁&0x7)≪10|B₂≪2|B₃≫6 )+1000
  • 第三组:( (B₃&0x3F)≪7|B₄≫1 )+1000

用户两端显示时应加分隔符或分行。

SAS 方法:emoji

HKDF 生成 6 字节,将前 42 位分为 7 组(每组 6 位),参照 base64,每组 6 位得 0~63 数字,查下表转为表情:

Number Emoji Unicode Description
0 🐶 U+1F436 Dog
1 🐱 U+1F431 Cat
2 🦁 U+1F981 Lion
3 🐎 U+1F40E Horse
4 🦄 U+1F984 Unicorn
5 🐷 U+1F437 Pig
6 🐘 U+1F418 Elephant
7 🐰 U+1F430 Rabbit
8 🐼 U+1F43C Panda
9 🐓 U+1F413 Rooster
10 🐧 U+1F427 Penguin
11 🐢 U+1F422 Turtle
12 🐟 U+1F41F Fish
13 🐙 U+1F419 Octopus
14 🦋 U+1F98B Butterfly
15 🌷 U+1F337 Flower
16 🌳 U+1F333 Tree
17 🌵 U+1F335 Cactus
18 🍄 U+1F344 Mushroom
19 🌏 U+1F30F Globe
20 🌙 U+1F319 Moon
21 ☁️ U+2601U+FE0F Cloud
22 🔥 U+1F525 Fire
23 🍌 U+1F34C Banana
24 🍎 U+1F34E Apple
25 🍓 U+1F353 Strawberry
26 🌽 U+1F33D Corn
27 🍕 U+1F355 Pizza
28 🎂 U+1F382 Cake
29 ❤️ U+2764U+FE0F Heart
30 😀 U+1F600 Smiley
31 🤖 U+1F916 Robot
32 🎩 U+1F3A9 Hat
33 👓 U+1F453 Glasses
34 🔧 U+1F527 Spanner
35 🎅 U+1F385 Santa
36 👍 U+1F44D Thumbs Up
37 ☂️ U+2602U+FE0F Umbrella
38 U+231B Hourglass
39 U+23F0 Clock
40 🎁 U+1F381 Gift
41 💡 U+1F4A1 Light Bulb
42 📕 U+1F4D5 Book
43 ✏️ U+270FU+FE0F Pencil
44 📎 U+1F4CE Paperclip
45 ✂️ U+2702U+FE0F Scissors
46 🔒 U+1F512 Lock
47 🔑 U+1F511 Key
48 🔨 U+1F528 Hammer
49 ☎️ U+260EU+FE0F Telephone
50 🏁 U+1F3C1 Flag
51 🚂 U+1F682 Train
52 🚲 U+1F6B2 Bicycle
53 ✈️ U+2708U+FE0F Aeroplane
54 🚀 U+1F680 Rocket
55 🏆 U+1F3C6 Trophy
56 U+26BD Ball
57 🎸 U+1F3B8 Guitar
58 🎺 U+1F3BA Trumpet
59 🔔 U+1F514 Bell
60 U+2693 Anchor
61 🎧 U+1F3A7 Headphones
62 📁 U+1F4C1 Folder
63 📌 U+1F4CC Pin

上述 Emoji 选择标准:

  • 无颜色即能辨识
  • 小图依然清晰
  • 各文化普遍识别
  • 互不相似,不易误认
  • 易用少量词描述
  • 无负面含义、平台表现一致性高

客户端应以所表描述或译文显示 Emoji。各客户端宜协作维护多语言译文集。

跨签名

跨签名功能,允许用户只需一次验证,就能信任对方今后新添加的设备(而无需依次手工验证对方全部设备)。每个用户有一套跨签名密钥:\

  • 主密钥(MSK):作为跨签名身份密钥,为用户用户主身份,对其他密钥签名;
  • 用户签名密钥(USK):仅本用户可见,用于为其他用户主密钥签名;
  • 自签名密钥(SSK):用于为本用户所有设备密钥签名。

主密钥还可为备份密钥签名。主密钥本身可用各自设备密钥签名,便于从设备验证迁移(如 Alice 先前已验证过 Bob 设备,Bob 设备已签主密钥,Alice 的设备可信任主密钥,并可用自己 USK 签之)。

用户通过 POST /_matrix/client/v3/keys/device_signing/upload API 上传跨签名密钥。Alice 若上传新密钥,其用户 ID 会自动出现在所有与她共享加密房间的用户 /sync 响应的 device_lists 字段的 changed 属性中。看到 Alice ID 后,Bob 应用 POST /_matrix/client/v3/keys/query 查询 Alice 的设备密钥与跨签名密钥。

如果 Alice 想给 Bob 发加密消息,则只要满足:

  • Alice 设备正用主密钥且已签 USK,
  • Alice USK 已签 Bob 主密钥,
  • Bob 主密钥已签其 SSK,
  • Bob 的 SSK 已签 Bob 的设备密钥,

即可信任 Bob 的设备。下图展示密钥签名关系:

    +------------------+                ..................   +----------------+
    | +--------------+ |   ..................            :   | +------------+ |
    | |              v v   v            :   :            v   v v            | |
    | |           +-----------+         :   :         +-----------+         | |
    | |           | Alice MSK |         :   :         |  Bob MSK  |         | |
    | |           +-----------+         :   :         +-----------+         | |
    | |             |       :           :   :           :       |           | |
    | |          +--+       :...        :   :        ...:       +--+        | |
    | |          v             v        :   :        v             v        | |
    | |    +-----------+ .............  :   :  ............. +-----------+  | |
    | |    | Alice SSK | : Alice USK :  :   :  :  Bob USK  : |  Bob SSK  |  | |
    | |    +-----------+ :...........:  :   :  :...........: +-----------+  | |
    | |      |  ...  |         :        :   :        :         |  ...  |    | |
    | |      V       V         :........:   :........:         V       V    | |
    | | +---------+   -+                                  +---------+   -+  | |
    | | | Devices | ...|                                  | Devices | ...|  | |
    | | +---------+   -+                                  +---------+   -+  | |
    | |      |  ...  |                                         |  ...  |    | |
    | +------+       |                                         |       +----+ |
    +----------------+                                         +--------------+

其中,方框代表密钥,箭头指示签名方向,虚线代表仅用户本人可见的键或签名。

Alice 视角下隐藏她不可见的密钥/签名:

    +------------------+                +----------------+   +----------------+
    | +--------------+ |                |                |   | +------------+ |
    | |              v v                |                v   v v            | |
    | |           +-----------+         |             +-----------+         | |
    | |           | Alice MSK |         |             |  Bob MSK  |         | |
    | |           +-----------+         |             +-----------+         | |
    | |             |       |           |                       |           | |
    | |          +--+       +--+        |                       +--+        | |
    | |          v             v        |                          v        | |
    | |    +-----------+ +-----------+  |                    +-----------+  | |
    | |    | Alice SSK | | Alice USK |  |                    |  Bob SSK  |  | |
    | |    +-----------+ +-----------+  |                    +-----------+  | |
    | |      |  ...  |         |        |                      |  ...  |    | |
    | |      V       V         +--------+                      V       V    | |
    | | +---------+   -+                                  +---------+   -+  | |
    | | | Devices | ...|                                  | Devices | ...|  | |
    | | +---------+   -+                                  +---------+   -+  | |
    | |      |  ...  |                                         |  ...  |    | |
    | +------+       |                                         |       +----+ |
    +----------------+                                         +--------------+

验证方法 也可直接用于验证主密钥:将其公钥(未填充 base64)做为“设备 ID”,按常规定义。例如,Alice 和 Bob 用 SAS 验证后,Alice 的 m.key.verification.mac 里可能有 "ed25519:alices+master+public+key": "alices+master+public+key"。因此服务器必须防止设备 ID 与跨签名公钥冲突。

私钥可借 Secrets 模块储存在服务器或分发给其他设备。分别用 m.cross_signing.master, m.cross_signing.user_signing, m.cross_signing.self_signing 名称标识,采用 base64 编码后加密。

密钥与签名安全

主密钥一旦泄露,攻击者即可冒充用户或让用户信任冒名顶替者。因此主密钥私钥必须严格安全储存。若客户端无安全存储能力(如无系统级密钥保护),严禁保存主密钥私钥。

看到其他用户更换主密钥,应提醒用户再决定是否继续通信。

由于设备 key ID (ed25519:DEVICE_ID) 与跨签名 key ID (ed25519:PUBLIC_KEY) 处于同一命名空间,客户端必须区分并用公钥实际内容定位验证目标。

服务器虽应禁止设备 ID 与跨签名密钥冲突,但仍须防范恶意服务器,所以客户端应注意:

  1. 在验证过程中用密钥公钥而不是仅用 key ID 识别密钥;
  2. 验证一开始就锁定目标密钥,并确保其在过程中未被更换;
  3. 如发现用户下设备 ID 与跨签名 key 相同,必须拒绝验证并弹警告。

用户签名与自签名密钥意在可被快速替换(如有泄露,仅需主密钥重签及适度重新验证)。但发现被攻破和重签都要耗用户精力,因此应优先安全存储私钥,否则干脆不存储,以权衡安全与便用。

为防社交网络泄露,服务器仅允许用户查阅:

  • 自己主密钥/自签/用户签名密钥的签名,
  • 自己设备对自己主密钥的签名,
  • 他人自签密钥对其设备的签名,
  • 他人主密钥对其自签密钥的签名,
  • 他人设备对其主密钥的签名。

用户无法看到其他人 user-signing key 的签名。

POST /_matrix/client/v3/keys/device_signing/upload


Added in v1.1

Changed in v1.11: UIA is not always required for this endpoint.

Publishes cross-signing keys for the user.

This API endpoint uses the User-Interactive Authentication API.

User-Interactive Authentication MUST be performed, except in these cases:

  • there is no existing cross-signing master key uploaded to the homeserver, OR
  • there is an existing cross-signing master key and it exactly matches the cross-signing master key provided in the request body. If there are any additional keys provided in the request (self-signing key, user-signing key) they MUST also match the existing keys stored on the server. In other words, the request contains no new keys.

This allows clients to freely upload one set of keys, but not modify/overwrite keys if they already exist. Allowing clients to upload the same set of keys more than once makes this endpoint idempotent in the case where the response is lost over the network, which would otherwise cause a UIA challenge upon retry.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
auth Authentication Data

Additional authentication information for the user-interactive authentication API.

master_key CrossSigningKey

Optional. The user's master key.

self_signing_key CrossSigningKey

Optional. The user's self-signing key. Must be signed by the accompanying master key, or by the user's most recently uploaded master key if no master key is included in the request.

user_signing_key CrossSigningKey

Optional. The user's user-signing key. Must be signed by the accompanying master key, or by the user's most recently uploaded master key if no master key is included in the request.

Authentication Data
Name Type Description
session string

The value of the session key given by the homeserver.

type string

The authentication type that the client is attempting to complete. May be omitted if session is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, via the fallback mechanism).

<Other properties>

Keys dependent on the login type

CrossSigningKey
Name Type Description
keys {string: string}

Required: The public key. The object must have exactly one property, whose name is in the form <algorithm>:<unpadded_base64_public_key>, and whose value is the unpadded base64 public key.

signatures Signatures

Signatures of the key, calculated using the process described at Signing JSON. Optional for the master key. Other keys must be signed by the user's master key.

usage [string]

Required: What the key is used for.

user_id string

Required: The ID of the user the key belongs to.

Request body example

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "master_key": {
    "keys": {
      "ed25519:base64+master+public+key": "base64+master+public+key"
    },
    "usage": [
      "master"
    ],
    "user_id": "@alice:example.com"
  },
  "self_signing_key": {
    "keys": {
      "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key"
    },
    "signatures": {
      "@alice:example.com": {
        "ed25519:base64+master+public+key": "signature+of+self+signing+key"
      }
    },
    "usage": [
      "self_signing"
    ],
    "user_id": "@alice:example.com"
  },
  "user_signing_key": {
    "keys": {
      "ed25519:base64+user+signing+public+key": "base64+user+signing+master+public+key"
    },
    "signatures": {
      "@alice:example.com": {
        "ed25519:base64+master+public+key": "signature+of+user+signing+key"
      }
    },
    "usage": [
      "user_signing"
    ],
    "user_id": "@alice:example.com"
  }
}

Responses

Status Description
200 The provided keys were successfully uploaded.
400

The input was invalid in some way. This can include one of the following error codes:

  • M_INVALID_SIGNATURE: For example, the self-signing or user-signing key had an incorrect signature.
  • M_MISSING_PARAM: No master key is available.
403 The public key of one of the keys is the same as one of the user's device IDs, or the request is not authorized for any other reason.

200 response

{}

400 response

{
  "errcode": "M_INVALID_SIGNATURE",
  "error": "Invalid signature"
}

403 response

{
  "errcode": "M_FORBIDDEN",
  "error": "Key ID in use"
}

POST /_matrix/client/v3/keys/signatures/upload


Added in v1.1

Publishes cross-signing signatures for the user.

The signed JSON object must match the key previously uploaded or retrieved for the given key ID, with the exception of the signatures property, which contains the new signature(s) to add.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Type Description
{User ID: {string: object}}

A map of user ID to a map of key ID to signed JSON object.

Request body example

{
  "@alice:example.com": {
    "HIJKLMN": {
      "algorithms": [
        "m.olm.v1.curve25519-aes-sha256",
        "m.megolm.v1.aes-sha"
      ],
      "device_id": "HIJKLMN",
      "keys": {
        "curve25519:HIJKLMN": "base64+curve25519+key",
        "ed25519:HIJKLMN": "base64+ed25519+key"
      },
      "signatures": {
        "@alice:example.com": {
          "ed25519:base64+self+signing+public+key": "base64+signature+of+HIJKLMN"
        }
      },
      "user_id": "@alice:example.com"
    },
    "base64+master+public+key": {
      "keys": {
        "ed25519:base64+master+public+key": "base64+master+public+key"
      },
      "signatures": {
        "@alice:example.com": {
          "ed25519:HIJKLMN": "base64+signature+of+master+key"
        }
      },
      "usage": [
        "master"
      ],
      "user_id": "@alice:example.com"
    }
  },
  "@bob:example.com": {
    "bobs+base64+master+public+key": {
      "keys": {
        "ed25519:bobs+base64+master+public+key": "bobs+base64+master+public+key"
      },
      "signatures": {
        "@alice:example.com": {
          "ed25519:base64+user+signing+public+key": "base64+signature+of+bobs+master+key"
        }
      },
      "usage": [
        "master"
      ],
      "user_id": "@bob:example.com"
    }
  }
}

Responses

Status Description
200 The provided signatures were processed.

200 response

Name Type Description
failures {User ID: {string: Error}}

A map from user ID to key ID to an error for any signatures that failed. If a signature was invalid, the errcode will be set to M_INVALID_SIGNATURE.

{
  "failures": {
    "@alice:example.com": {
      "HIJKLMN": {
        "errcode": "M_INVALID_SIGNATURE",
        "error": "Invalid signature"
      }
    }
  }
}
二维码

[Added in v1.1]

二维码验证适用于一方设备支持扫码,可快速验证。二维码内容编码双方主签名密钥及一组随机共享密钥供单次扫描双向验证。

若支持显示二维码,客户端在 m.key.verification.requestm.key.verification.readymethods 字段中声明 m.qr_code.show.v1m.reciprocate.v1。若支持扫码,则用 m.qr_code.scan.v1m.reciprocate.v1。如果既支持显示又支持扫码,则全部声明。

Alice、Bob 互验证流程:

  1. Alice 和 Bob 面对面,欲验证钥匙。

  2. 启动验证流程。

  3. Alice 客户端显示二维码,若 Bob 客户端能扫码则 Bob 可选扫码;Bob 客户端也可以显示二维码或选择扫码。二维码格式见下文。其他验证方式如 SAS Emoji 可并列提供。

  4. Alice 扫描 Bob 的二维码。

  5. Alice 设备校验扫码内容是否为期望的公钥。如失败则报错同时发送 m.key.verification.cancel 给 Bob。

    否则

    • 此时 Alice 已信任 Bob 密钥,
    • 并知道 Bob 拥有 Alice 的正确密钥。 接下来 Alice 需告知 Bob 验证结果以使其信任 Alice 密钥。
  6. Alice 设备显示验证成功;Bob 设备尚未通过验证(需等待 Alice 明确反馈),用户需人工看到 Alice 已同意。

  7. Alice 设备发送 m.key.verification.start(method=m.reciprocate.v1) 给 Bob,包含共享密钥。仅作信号用,无验证功效。

  8. Bob 收到上述消息,校验共享密钥。如不符则报错(这不影响 Alice 对 Bob 的验证);如一致,则请求 Bob 手动确认已经被验证。

  9. Bob 见 Alice 端确认密钥一致后,点按钮确认验证。

    Bob 信任 Alice,依据于 Alice 现场告知已验证成功。恶意 Alice 欺骗只影响自己与 Bob 通信,Alice 没动力作假。因而只要通信媒介可靠(如真人言语),这一流程足以可信。

  10. 双方退回 m.key.verification.done

二维码格式

二维码必须兼容 ISO/IEC 18004:2015,仅使用字节模式单分段。

纠错级别由展示端自行选择。

二进制内容结构如下:

  • ASCII “MATRIX”,各字节编码分别为 0x4D, 0x41, 0x54, 0x52, 0x49, 0x58
  • 1 字节,二维码版本(须为 0x02)
  • 1 字节,二维码验证模式,值为:
    • 0x00 验证其他用户(跨签名)
    • 0x01 本端信任主密钥情况下自验证
    • 0x02 本端尚未信任主密钥的自验证
  • 关联验证事件的 event ID 或 transaction_id,方式为:
    • 2 字节,网络字节序,长度
    • 实际 UTF-8 字符串编码的 ID
  • 第一个 32 字节密钥,含义:
    • 若 mode==0x00 或 0x01,则本用户主跨签名公钥
    • 若 mode==0x02,则本设备 Ed25519 签名密钥
  • 第二个 32 字节密钥,含义:
    • 若 mode==0x00,则为他人主跨签名公钥
    • 若 mode==0x01,则为他人设备 Ed25519 公钥
    • 若 mode==0x02,为本用户主跨签名公钥
  • 一组随机共享密钥(推荐约 8 字节),为编码内容的剩余部分

实例:Alice 的二维码内容

      "MATRIX"    |ver|mode| len   | event ID
 4D 41 54 52 49 58  02  00   00 2D   21 41 42 43 44 ...
| 用户主密钥              | 对方主密钥                   | 共享密钥
  00 01 02 03 04 05 06 07 ...   10 11 12 13 14 15 16 17 ...      20 21 22 23 24 25 26 27

代表 Alice 验证 Bob,在事件 “$ABCD…” 下自认主密钥为 0001020304050607... (base64: “AAECAwQFBg…"),她认为 Bob 的主密钥为 1011121314151617... (base64: “EBESExQVFh…"),共享密钥为 2021222324252627 (base64: “ICEiIyQlJic”)。

二维码专用验证消息

m.key.verification.start with method: m.reciprocate.v1


Begins a key verification process using the m.reciprocate.v1 method, after scanning a QR code.

Event type: Message event

Content

Name Type Description
from_device string

Required: The device ID which is initiating the process.

m.relates_to VerificationRelatesTo

Required when sent as an in-room message. Indicates the m.key.verification.request that this message is related to. Note that for encrypted messages, this property should be in the unencrypted portion of the event.

method string

Required: The verification method to use.

One of: [m.reciprocate.v1].

secret string

Required: The shared secret from the QR code, encoded using unpadded base64.

transaction_id string

Required when sent as a to-device message. An opaque identifier for the verification process. Must be unique with respect to the devices involved. Must be the same as the transaction_id given in the m.key.verification.request if this process is originating from a request.

VerificationRelatesTo
Name Type Description
event_id string

The event ID of the m.key.verification.request that this message is related to.

rel_type string

The relationship type. Currently, this can only be an m.reference relationship type.

One of: [m.reference].

Examples

设备间共享密钥

Bob 若在电脑端与 Alice 有加密对话,在手机端首次登入时,或希望能访问到历史消息。为此本协议支持若干跨设备密钥转移方式。

密钥请求

如果设备缺失解密信息所需的密钥,可向其他设备发 m.room_key_request to-device 消息,请求字段 action 设为 request

其他设备同意分享密钥后,可通过加密的 m.forwarded_room_key to-device 消息发送给请求设备。请求设备收到后,需向所有原发出请求的设备发 request_cancellationm.room_key_request 通知取消,接收端一旦收到 request_cancellation 就应忽视所有同一 request_idrequesting_device_id 的早前请求。

如设备决定不共享密钥,可以发 m.room_key.withheld 以反馈拒绝加密密钥分享,详见报告加密密钥被拒绝

密钥分享本身是攻击点,必须谨慎对待。客户端应只向受信任同一用户的设备请求/发密钥,并只接受来自受信任同一用户设备的转发密钥。

服务器端密钥备份

设备可将加密密钥上传服务器做加密备份。需解密某消息时,设备可向服务器请求该密钥并解密。备份为每用户维护,用户可重置覆盖已有备份。

相比密钥请求,服务器备份无需在线设备即可获取密钥。但会话密钥在服务器以加密形式存储,客户端需有解密密钥 方可解密备份。

创建备份时,客户端调用 POST /_matrix/client/v3/room_keys/version,加密方式定义于 auth_data。其他客户端用 GET /_matrix/client/v3/room_keys/version 发现备份。密钥随后按备份的 auth_data 加密,并用 PUT /_matrix/client/v3/room_keys/keys 或其相关变体上传,可用 GET /_matrix/client/v3/room_keys/keys 或变体下载。一次仅能写入最新备份版本。也可用 DELETE /_matrix/client/v3/room_keys/version/{version}DELETE /_matrix/client/v3/room_keys/keys 等方式删除备份或部分密钥。

客户端上传密钥前,须确保 auth_data 已被信任。可通过:

  • 检查其是否由用户主跨签名密钥或受信设备签名
  • 或用私钥本地推导出并验证公钥是否一致。受信私钥获取方式包括用户自己输入、从秘密存储读取,或经秘密共享自本用户受信设备拉取密钥。

如果上传会话密钥已存在,服务器对比密钥元数据保留或覆盖,规则如下:

  • 若有 is_verified 字段,优先保留设为 true 的;
  • 若两者都同等,则选择 first_message_index 更小者;
  • 最后由 forwarded_count 更小者获保留。
解密密钥

通常,解密钥匙(即密钥的私有部分)会以 Secrets 模块方式存储服务器或发送给其他设备,采用 m.megolm_backup.v1 名称,且加密前为 base64 编码。

如用户直接复制密钥,则以通用加密密钥表示法为字符串展示。

本规范早前使用“恢复密钥”一词,但各客户端 UI 通常用该词指秘密存储密钥,为避免歧义,现不再使用该说法。

备份算法:m.megolm_backup.v1.curve25519-aes-sha2

若备份的 algorithmm.megolm_backup.v1.curve25519-aes-sha2,则 auth_data 结构如下:

AuthData


The format of the auth_data when a key backup is created with the algorithm set to m.megolm_backup.v1.curve25519-aes-sha2.

AuthData
Name Type Description
public_key string

Required: The curve25519 public key used to encrypt the backups, encoded in unpadded base64.

signatures object

Signatures of the auth_data, as Signed JSON

Examples

{
  "public_key": "abcdefg",
  "signatures": {
    "something": {
      "ed25519:something": "hijklmnop"
    }
  }
}

备份的 session_data 字段生成步骤:

  1. 把要备份的会话密钥编码为 BackedUpSessionData 格式的 JSON 对象。

  2. 生成临时 curve25519 密钥,并用它和备份公钥做 ECDH 得共享密钥。临时公钥(未填充 base64)存为 ephemeral 字段。

  3. 以共享密钥做 HKDF(哈希算法为 SHA-256,盐为 32 字节全 0,info 为空字符串),得 80 字节。前 32 字节作 AES 密钥,下 32 字节作 MAC 密钥,后 16 字节作 AES 初始化向量。

  4. JSON 序列化,加密方式为 AES-CBC-256/PKCS#7,密文未填充 base64 编码存于 ciphertext

  5. 用 MAC 密钥计算 HMAC-SHA-256(消息体为空),取前 8 字节转换为 base64 存为 mac 字段。

第五步本意应对原始密文做 HMAC,但 libolm 实现失误导致实际传递空字符串。未来规范将修正此问题。参见 MSC4048

BackedUpSessionData


The format of a backed-up session key, prior to encryption, when using the m.megolm_backup.v1.curve25519-aes-sha2 algorithm.

BackedUpSessionData
Name Type Description
algorithm string

Required: The end-to-end message encryption algorithm that the key is for. Must be m.megolm.v1.aes-sha2.

forwarding_curve25519_key_chain [string]

Required: Chain of Curve25519 keys through which this session was forwarded, via m.forwarded_room_key events.

sender_claimed_keys {string: string}

Required: A map from algorithm name (ed25519) to the Ed25519 signing key of the sending device.

sender_key string

Required: Unpadded base64-encoded device Curve25519 key.

session_key string

Required: Unpadded base64-encoded session key in session-export format.

Examples

{
  "algorithm": "m.megolm.v1.aes-sha2",
  "forwarding_curve25519_key_chain": [
    "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
  ],
  "sender_claimed_keys": {
    "ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y"
  },
  "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
  "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..."
}

GET /_matrix/client/v3/room_keys/keys


Added in v1.1

Retrieve the keys from the backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
version string

Required: The backup from which to retrieve the keys.


Responses

Status Description
200 The key data. If no keys are found, then an object with an empty rooms property will be returned ({"rooms": {}}).
404 The backup was not found.
429 This request was rate-limited.

200 response

Name Type Description
rooms {Room ID: RoomKeyBackup}

Required: A map of room IDs to room key backup data.

RoomKeyBackup
Name Type Description
sessions {string: KeyBackupData}

Required: A map of session IDs to key data.

KeyBackupData
Name Type Description
first_message_index integer

Required: The index of the first message in the session that the key can decrypt.

forwarded_count integer

Required: The number of times this key has been forwarded via key-sharing between devices.

is_verified boolean

Required: Whether the device backing up the key verified the device that the key is from.

session_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

{
  "rooms": {
    "!room:example.org": {
      "sessions": {
        "sessionid1": {
          "first_message_index": 1,
          "forwarded_count": 0,
          "is_verified": true,
          "session_data": {
            "ciphertext": "base64+ciphertext+of+JSON+data",
            "ephemeral": "base64+ephemeral+key",
            "mac": "base64+mac+of+ciphertext"
          }
        }
      }
    }
  }
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

PUT /_matrix/client/v3/room_keys/keys


Added in v1.1

Store several keys in the backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
version string

Required: The backup in which to store the keys. Must be the current backup.

Request body

Name Type Description
rooms {Room ID: RoomKeyBackup}

Required: A map of room IDs to room key backup data.

RoomKeyBackup
Name Type Description
sessions {string: KeyBackupData}

Required: A map of session IDs to key data.

KeyBackupData
Name Type Description
first_message_index integer

Required: The index of the first message in the session that the key can decrypt.

forwarded_count integer

Required: The number of times this key has been forwarded via key-sharing between devices.

is_verified boolean

Required: Whether the device backing up the key verified the device that the key is from.

session_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

Request body example

{
  "rooms": {
    "!room:example.org": {
      "sessions": {
        "sessionid1": {
          "first_message_index": 1,
          "forwarded_count": 0,
          "is_verified": true,
          "session_data": {
            "ciphertext": "base64+ciphertext+of+JSON+data",
            "ephemeral": "base64+ephemeral+key",
            "mac": "base64+mac+of+ciphertext"
          }
        }
      }
    }
  }
}

Responses

Status Description
200 The update succeeded
403 The version specified does not match the current backup version. The current version will be included in the current_version field.
404 The backup was not found.
429 This request was rate-limited.

200 response

RoomKeysUpdateResponse
Name Type Description
count integer

Required: The number of keys stored in the backup

etag string

Required: The new etag value representing stored keys in the backup.

See GET /room_keys/version/{version} for more details.

{
  "count": 10,
  "etag": "abcdefg"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "current_version": "42",
  "errcode": "M_WRONG_ROOM_KEYS_VERSION",
  "error": "Wrong backup version."
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

DELETE /_matrix/client/v3/room_keys/keys


Added in v1.1

Delete the keys from the backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
version string

Required: The backup from which to delete the key


Responses

Status Description
200 The update succeeded
404 The backup was not found.
429 This request was rate-limited.

200 response

RoomKeysUpdateResponse
Name Type Description
count integer

Required: The number of keys stored in the backup

etag string

Required: The new etag value representing stored keys in the backup.

See GET /room_keys/version/{version} for more details.

{
  "count": 10,
  "etag": "abcdefg"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/room_keys/keys/{roomId}


Added in v1.1

Retrieve the keys from the backup for a given room.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room that the requested key is for.

query parameters
Name Type Description
version string

Required: The backup from which to retrieve the key.


Responses

Status Description
200 The key data. If no keys are found, then an object with an empty sessions property will be returned ({"sessions": {}}).
404 The backup was not found.
429 This request was rate-limited.

200 response

RoomKeyBackup
Name Type Description
sessions {string: KeyBackupData}

Required: A map of session IDs to key data.

KeyBackupData
Name Type Description
first_message_index integer

Required: The index of the first message in the session that the key can decrypt.

forwarded_count integer

Required: The number of times this key has been forwarded via key-sharing between devices.

is_verified boolean

Required: Whether the device backing up the key verified the device that the key is from.

session_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

{
  "sessions": {
    "sessionid1": {
      "first_message_index": 1,
      "forwarded_count": 0,
      "is_verified": true,
      "session_data": {
        "ciphertext": "base64+ciphertext+of+JSON+data",
        "ephemeral": "base64+ephemeral+key",
        "mac": "base64+mac+of+ciphertext"
      }
    }
  }
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

PUT /_matrix/client/v3/room_keys/keys/{roomId}


Added in v1.1

Store several keys in the backup for a given room.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room that the keys are for.

query parameters
Name Type Description
version string

Required: The backup in which to store the keys. Must be the current backup.

Request body

RoomKeyBackup
Name Type Description
sessions {string: KeyBackupData}

Required: A map of session IDs to key data.

KeyBackupData
Name Type Description
first_message_index integer

Required: The index of the first message in the session that the key can decrypt.

forwarded_count integer

Required: The number of times this key has been forwarded via key-sharing between devices.

is_verified boolean

Required: Whether the device backing up the key verified the device that the key is from.

session_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

Request body example

{
  "sessions": {
    "sessionid1": {
      "first_message_index": 1,
      "forwarded_count": 0,
      "is_verified": true,
      "session_data": {
        "ciphertext": "base64+ciphertext+of+JSON+data",
        "ephemeral": "base64+ephemeral+key",
        "mac": "base64+mac+of+ciphertext"
      }
    }
  }
}

Responses

Status Description
200 The update succeeded
403 The version specified does not match the current backup version. The current version will be included in the current_version field.
404 The backup was not found.
429 This request was rate-limited.

200 response

RoomKeysUpdateResponse
Name Type Description
count integer

Required: The number of keys stored in the backup

etag string

Required: The new etag value representing stored keys in the backup.

See GET /room_keys/version/{version} for more details.

{
  "count": 10,
  "etag": "abcdefg"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "current_version": "42",
  "errcode": "M_WRONG_ROOM_KEYS_VERSION",
  "error": "Wrong backup version."
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

DELETE /_matrix/client/v3/room_keys/keys/{roomId}


Added in v1.1

Delete the keys from the backup for a given room.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room that the specified key is for.

query parameters
Name Type Description
version string

Required: The backup from which to delete the key.


Responses

Status Description
200 The update succeeded
404 The backup was not found.
429 This request was rate-limited.

200 response

RoomKeysUpdateResponse
Name Type Description
count integer

Required: The number of keys stored in the backup

etag string

Required: The new etag value representing stored keys in the backup.

See GET /room_keys/version/{version} for more details.

{
  "count": 10,
  "etag": "abcdefg"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/room_keys/keys/{roomId}/{sessionId}


Added in v1.1

Retrieve a key from the backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room that the requested key is for.

sessionId string

Required: The ID of the megolm session whose key is requested.

query parameters
Name Type Description
version string

Required: The backup from which to retrieve the key.


Responses

Status Description
200 The key data
404 The key or backup was not found.
429 This request was rate-limited.

200 response

KeyBackupData
Name Type Description
first_message_index integer

Required: The index of the first message in the session that the key can decrypt.

forwarded_count integer

Required: The number of times this key has been forwarded via key-sharing between devices.

is_verified boolean

Required: Whether the device backing up the key verified the device that the key is from.

session_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

{
  "first_message_index": 1,
  "session_data": {
    "ciphertext": "base64+ciphertext+of+JSON+data",
    "ephemeral": "base64+ephemeral+key",
    "mac": "base64+mac+of+ciphertext"
  }
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Key not found."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

PUT /_matrix/client/v3/room_keys/keys/{roomId}/{sessionId}


Added in v1.1

Store a key in the backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room that the key is for.

sessionId string

Required: The ID of the megolm session that the key is for.

query parameters
Name Type Description
version string

Required: The backup in which to store the key. Must be the current backup.

Request body

KeyBackupData
Name Type Description
first_message_index integer

Required: The index of the first message in the session that the key can decrypt.

forwarded_count integer

Required: The number of times this key has been forwarded via key-sharing between devices.

is_verified boolean

Required: Whether the device backing up the key verified the device that the key is from.

session_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

Request body example

{
  "first_message_index": 1,
  "session_data": {
    "ciphertext": "base64+ciphertext+of+JSON+data",
    "ephemeral": "base64+ephemeral+key",
    "mac": "base64+mac+of+ciphertext"
  }
}

Responses

Status Description
200 The update succeeded.
403 The version specified does not match the current backup version. The current version will be included in the current_version field.
429 This request was rate-limited.

200 response

RoomKeysUpdateResponse
Name Type Description
count integer

Required: The number of keys stored in the backup

etag string

Required: The new etag value representing stored keys in the backup.

See GET /room_keys/version/{version} for more details.

{
  "count": 10,
  "etag": "abcdefg"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "current_version": "42",
  "errcode": "M_WRONG_ROOM_KEYS_VERSION",
  "error": "Wrong backup version."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

DELETE /_matrix/client/v3/room_keys/keys/{roomId}/{sessionId}


Added in v1.1

Delete a key from the backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room that the specified key is for.

sessionId string

Required: The ID of the megolm session whose key is to be deleted.

query parameters
Name Type Description
version string

Required: The backup from which to delete the key


Responses

Status Description
200 The update succeeded
404 The backup was not found.
429 This request was rate-limited.

200 response

RoomKeysUpdateResponse
Name Type Description
count integer

Required: The number of keys stored in the backup

etag string

Required: The new etag value representing stored keys in the backup.

See GET /room_keys/version/{version} for more details.

{
  "count": 10,
  "etag": "abcdefg"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/room_keys/version


Added in v1.1

Get information about the latest backup version.

Rate-limited: Yes
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The information about the backup.
404 No backup exists.
429 This request was rate-limited.

200 response

Name Type Description
algorithm string

Required: The algorithm used for storing backups.

One of: [m.megolm_backup.v1.curve25519-aes-sha2].

auth_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

count integer

Required: The number of keys stored in the backup.

etag string

Required: An opaque string representing stored keys in the backup. Clients can compare it with the etag value they received in the request of their last key storage request. If not equal, another client has modified the backup.

version string

Required: The backup version.

{
  "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
  "auth_data": {
    "public_key": "abcdefg",
    "signatures": {
      "@alice:example.org": {
        "ed25519:deviceid": "signature"
      }
    }
  },
  "count": 42,
  "etag": "anopaquestring",
  "version": "1"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "No current backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/room_keys/version


Added in v1.1

Creates a new backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request body

Name Type Description
algorithm string

Required: The algorithm used for storing backups.

One of: [m.megolm_backup.v1.curve25519-aes-sha2].

auth_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

Request body example

{
  "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
  "auth_data": {
    "public_key": "abcdefg",
    "signatures": {
      "@alice:example.org": {
        "ed25519:deviceid": "signature"
      }
    }
  }
}

Responses

Status Description
200 The version id of the new backup.
429 This request was rate-limited.

200 response

Name Type Description
version string

Required: The backup version. This is an opaque string.

{
  "version": "1"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

GET /_matrix/client/v3/room_keys/version/{version}


Added in v1.1

Get information about an existing backup.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
version string

Required: The backup version to get, as returned in the version parameter of the response in POST /_matrix/client/v3/room_keys/version or this endpoint.


Responses

Status Description
200 The information about the requested backup.
404 The backup specified does not exist.
429 This request was rate-limited.

200 response

Name Type Description
algorithm string

Required: The algorithm used for storing backups.

One of: [m.megolm_backup.v1.curve25519-aes-sha2].

auth_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

count integer

Required: The number of keys stored in the backup.

etag string

Required: An opaque string representing stored keys in the backup. Clients can compare it with the etag value they received in the request of their last key storage request. If not equal, another client has modified the backup.

version string

Required: The backup version.

{
  "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
  "auth_data": {
    "public_key": "abcdefg",
    "signatures": {
      "@alice:example.org": {
        "ed25519:deviceid": "signature"
      }
    }
  },
  "count": 42,
  "etag": "anopaquestring",
  "version": "1"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

PUT /_matrix/client/v3/room_keys/version/{version}


Added in v1.1

Update information about an existing backup. Only auth_data can be modified.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
version string

Required: The backup version to update, as returned in the version parameter in the response of POST /_matrix/client/v3/room_keys/version or GET /_matrix/client/v3/room_keys/version/{version}.

Request body

Name Type Description
algorithm string

Required: The algorithm used for storing backups. Must be the same as the algorithm currently used by the backup.

One of: [m.megolm_backup.v1.curve25519-aes-sha2].

auth_data object

Required: Algorithm-dependent data. See the documentation for the backup algorithms in Server-side key backups for more information on the expected format of the data.

version string

The backup version. If present, must be the same as the version in the path parameter.

Request body example

{
  "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
  "auth_data": {
    "public_key": "abcdefg",
    "signatures": {
      "@alice:example.org": {
        "ed25519:deviceid": "signature"
      }
    }
  },
  "version": "1"
}

Responses

Status Description
200 The update succeeded.
400 A parameter was incorrect. For example, the algorithm does not match the current backup algorithm, or the version in the body does not match the version in the path.
404 The backup specified does not exist.
429 This request was rate-limited.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "Algorithm does not match"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

DELETE /_matrix/client/v3/room_keys/version/{version}


Added in v1.1

Delete an existing key backup. Both the information about the backup, as well as all key data related to the backup will be deleted.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
version string

Required: The backup version to delete, as returned in the version parameter in the response of POST /_matrix/client/v3/room_keys/version or GET /_matrix/client/v3/room_keys/version/{version}.


Responses

Status Description
200 The delete succeeded, or the specified backup was previously deleted.
404 The backup specified does not exist. If the backup was previously deleted, the call should succeed rather than returning an error.
429 This request was rate-limited.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Unknown backup version"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
密钥导出

密钥可手工导出成加密文件,经用户复制后导入另一设备。文件加密方式如下:

  1. 会话数据以 Key export format JSON 对象格式编码。

  2. 用户口令经 PBKDF2(HMAC-SHA-512, password, S, N, 512) 推导 512 位密钥。S 为 128 比特随机盐,N 迭代次数(至少 10 万)。K, K’ 为前后 256 比特,K 为 AES-256 密钥,K’ 供 HMAC-SHA-256。

  3. JSON 字符串化后用 AES-CTR-256/K 加密,IV 预设为 128 比特安全随机数且 bit 63 为零(兼容实现差异)。

  4. 按顺序拼接如下:

长度(字节) 描述
1 导出格式版本,须为 0x01
16 盐 S。
16 初始化向量 IV。
4 N,32 位大端整数。
变长 加密 JSON。
32 以上所有数据用 K’ 做 HMAC-SHA-256 后的结果。
  1. 整体 base64 编码。可适当换行。

  2. 最终整体包裹于 -----BEGIN MEGOLM SESSION DATA-----\n\n-----END MEGOLM SESSION DATA-----\n

密钥导出格式

导出会话为 ExportedSessionData JSON 数组,具体定义:

ExportedSessionData


The format used to encode a Megolm session key for export.

This is similar to the format before encryption used for the session keys in Server-side key backups but adds the room_id and session_id fields.

ExportedSessionData
Name Type Description
algorithm string

Required: The end-to-end message encryption algorithm that the key is for. Must be m.megolm.v1.aes-sha2.

forwarding_curve25519_key_chain [string]

Required: Chain of Curve25519 keys through which this session was forwarded, via m.forwarded_room_key events.

room_id string

Required: The room where the session is used.

sender_claimed_keys {string: string}

Required: A map from algorithm name (ed25519) to the Ed25519 signing key of the sending device.

sender_key string

Required: Unpadded base64-encoded device Curve25519 key.

session_id string

Required: The Megolm session ID.

session_key string

Required: Unpadded base64-encoded session key in session-export format.

Examples

{
  "algorithm": "m.megolm.v1.aes-sha2",
  "forwarding_curve25519_key_chain": [
    "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
  ],
  "sender_claimed_keys": {
    "ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y"
  },
  "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
  "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..."
}

消息算法

消息算法命名

消息算法命名使用全规范内统一扩展格式。以 m. 开头的算法名保留为本规范定义。自定义算法应按 Java 包规范全局唯一命名。

算法名应简短清晰,并表明所用原始算法,以便判断安全性。例如:

m.olm.v1 太短,识别度低且难于扩展。
m.olm.v1.ecdh-curve25519-hdkfsha256.hmacsha256.hkdfsha256-aes256-cbc-hmac64sha256 太冗长且损耗带宽、可读性差。

m.olm.v1.curve25519-aes-sha2

此名代表 Olm 协议 v1,见 Olm 规范。其组成:

  • Curve25519 初始密钥协商
  • HKDF-SHA-256 密钥推进
  • Curve25519 用作根密钥推进
  • HMAC-SHA-256 推进主键
  • HKDF-SHA-256,AES-256-CBC,8 字节 HMAC-SHA-256 验证加密

支持 Olm 的设备必须将 “m.olm.v1.curve25519-aes-sha2” 纳入支持算法列表,发布 Curve25519 设备密钥和一次性密钥。

一份 Olm 加密的事件:

{
  "type": "m.room.encrypted",
  "content": {
    "algorithm": "m.olm.v1.curve25519-aes-sha2",
    "sender_key": "<sender_curve25519_key>",
    "ciphertext": {
      "<device_curve25519_key>": {
        "type": 0,
        "body": "<encrypted_payload_base_64>"
      }
    }
  }
}

ciphertext 为设备 Curve25519 公钥到加密负载的映射。body 为 Base64 编码的 Olm 消息内容。type 整数:0 为初始 key,1 为后续普通消息。

Olm 会话发送消息前,均为类型 0;收到对端消息后,转为类型 1。

客户端收到类型 0 消息,需先查是否已有匹配会话;若没有则新建并尝试解密,解密成功前不得持久化会话或销毁一次性密钥。

类型 1 需已有会话才能解密,若无会话,则视为无效消息。

明文负载如下:

{
  "type": "<type of the plaintext event>",
  "content": "<content for the plaintext event>",
  "sender": "<sender_user_id>",
  "recipient": "<recipient_user_id>",
  "recipient_keys": {
    "ed25519": "<our_ed25519_key>"
  },
  "keys": {
    "ed25519": "<sender_ed25519_key>"
  }
}

type 与 content 对应具体消息类型与内容。

这些字段用于防止攻击者冒名发 curve25519 公钥假冒自己。sender 应为发送者用户,recipient 为本地用户,recipient_keys 标明本端 ed25519。

客户端需确认加密消息正文中 sender_key 和解密明文中的 keys.ed25519/keys/query 查询到的密钥相符。还需核实密钥签名。否则无法确认发送设备拥有所声称 ed25519 私钥,这对经过验证设备尤为重要。

如与对方建立了多个会话,应选用最近收到且成功解密过消息的那个。若尚无消息则以建立时间论新旧。为避免膨胀,可为每个设备设一个最大会话数(至少 4),采用 LRU 策略淘汰旧会话。

恢复不可解密 Olm 消息

有时消息因各种原因无法解密。此时应假定 Olm 会话失效,需要新建会话。

Megolm 加密消息通常不会这样。未解密的消息一般密钥随后可获得。但 Olm 无此恢复机制,故必须新建会话。

新建会话时,需向对端发送 m.dummy 事件通知会话变更。

客户端应限速,不得一小时内反复新建会话。

可通过 m.room_key_request 请求帮助找回因失效而丢失的 Megolm 会话密钥。

对于未知 Megolm 会话的密钥请求,应广播给该用户的所有设备(不只当前 event 的 device_id 或 sender_key),因这些字段已废弃。见 m.megolm.v1.aes-sha2

m.megolm.v1.aes-sha2

[Changed in v1.3]

m.megolm.v1.aes-sha2 代表 Megolm 算法 v1, 详见 Megolm 规范。详细:

  • HMAC-SHA-256 连续哈希推进
  • HKDF-SHA-256,AES-256-CBC,加 8 字节 HMAC-SHA-256 验证
  • Ed25519 签名消息

支持 Megolm 的设备即需支持 Olm,且将本算法纳入支持算法列表。

加密事件格式:

{
  "type": "m.room.encrypted",
  "content": {
    "algorithm": "m.megolm.v1.aes-sha2",
    "sender_key": "<sender_curve25519_key>",
    "device_id": "<sender_device_id>",
    "session_id": "<outbound_group_session_id>",
    "ciphertext": "<encrypted_payload_base_64>"
  }
}

明文负载为:

{
  "type": "<event_type>",
  "content": "<event_content>",
  "room_id": "<the room_id>"
}

room_id 写入明文防止服务器篡改房间。

客户端须防范重放攻击,记录 Megolm ratchet index,应拒绝重复 index 的消息(须避免误杀,如正常流程可能重复解密一条消息)。

同 Olm,客户端需确认消息发送人即明文 sender 字段,其房间与 session_id 已被本端信任记录。

v1.3 起,sender_keydevice_id 字段已废弃。应继续发送,但不得用其校验消息来源。

客户端不得用这两字段存储/检索会话。

将来规范版本中,这些字段将完全移除。

移除此类字段,提升隐私和安全性,主设备不可见、降低对不受信数据(服务器可篡改、用户故意作假)的依赖。

session_id 本身全局唯一,无需额外 context 字段。

减少此依赖同时提升隐私与安全性。

要在房间启用端到端加密,客户端可发 m.room.encryption 状态事件,algorithmm.megolm.v1.aes-sha2

房间新建 Megolm 会话后,需用 Olm 私信分发 session key 给目标设备,以便其解密今后消息。密钥由 m.room_key 事件发送。收到他人密钥后,须存储以便解密消息。

收到会话密钥时,必须确保密钥由 Olm channel 安全获得,以确认消息真实性。

当客户端要更新 Megolm 会话数据时,必须确保新数据仅来自可信来源(如本用户已验证设备的 m.forwarded_room_keym.room_key),且新密钥的 message index 必须小于已有密钥。

协议定义

事件

m.room.encryption


Defines how messages sent in this room should be encrypted.

Event type: State event
State key A zero-length string.

Content

Name Type Description
algorithm string

Required: The encryption algorithm to be used to encrypt messages sent in this room.

One of: [m.megolm.v1.aes-sha2].

rotation_period_ms integer

How long the session should be used before changing it. 604800000 (a week) is the recommended default.

rotation_period_msgs integer

How many messages should be sent before changing the session. 100 is the recommended default.

Examples

{
  "content": {
    "algorithm": "m.megolm.v1.aes-sha2",
    "rotation_period_ms": 604800000,
    "rotation_period_msgs": 100
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.encryption",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room.encrypted


This event type is used when sending encrypted events. It can be used either within a room (in which case it will have all of the normal properties in Room events), or as a to-device event.

Event type: Message event

Content

Name Type Description
algorithm string

Required: The encryption algorithm used to encrypt this event. The value of this field determines which other properties will be present.

One of: [m.olm.v1.curve25519-aes-sha2, m.megolm.v1.aes-sha2].

ciphertext string|{string: CiphertextInfo}

Required: The encrypted content of the event. Either the encrypted payload itself, in the case of a Megolm event, or a map from the recipient Curve25519 identity key to ciphertext information, in the case of an Olm event. For more details, see Messaging Algorithms.

device_id string

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 for more information.

Changed in v1.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 for more information.

sender_key string

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 for more information.

Changed in v1.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 for more information.

session_id string

The ID of the session used to encrypt the message. Required with Megolm.

CiphertextInfo
Name Type Description
body string

The encrypted payload.

type integer

The Olm message type.

Examples

{
  "content": {
    "algorithm": "m.megolm.v1.aes-sha2",
    "ciphertext": "AwgAEnACgAkLmt6qF84IK++J7UDH2Za1YVchHyprqTqsg...",
    "device_id": "RJYKSTBOIE",
    "sender_key": "IlRMeOPX2e0MurIyfWEucYBRVOEEUMrOHqn/8mLqMjA",
    "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.encrypted",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}
{
  "content": {
    "algorithm": "m.olm.v1.curve25519-aes-sha2",
    "ciphertext": {
      "7qZcfnBmbEGzxxaWfBjElJuvn7BZx+lSz/SvFrDF/z8": {
        "body": "AwogGJJzMhf/S3GQFXAOrCZ3iKyGU5ZScVtjI0KypTYrW...",
        "type": 0
      }
    },
    "sender_key": "Szl29ksW/L8yZGWAX+8dY1XyFi+i5wm+DRhTGkbMiwU"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.encrypted",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.room_key


This event type is used to exchange keys for end-to-end encryption. It is encrypted as an m.room.encrypted event using Olm, then sent as a to-device event.

Event type: Message event

Content

Name Type Description
algorithm string

Required: The encryption algorithm the key in this event is to be used with.

One of: [m.megolm.v1.aes-sha2].

room_id string

Required: The room where the key is used.

session_id string

Required: The ID of the session that the key is for.

session_key string

Required: The key to be exchanged.

Examples

{
  "content": {
    "algorithm": "m.megolm.v1.aes-sha2",
    "room_id": "!Cuyf34gef24t:localhost",
    "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
    "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8LlfJL7qNBEY..."
  },
  "type": "m.room_key"
}

m.room_key_request


This event type is used to request keys for end-to-end encryption. It is sent as an unencrypted to-device event.

Event type: Message event

Content

Name Type Description
action string

Required:

One of: [request, request_cancellation].

body RequestedKeyInfo

Information about the requested key. Required when action is request.

request_id string

Required: A random string uniquely identifying the request for a key. If the key is requested multiple times, it should be reused. It should also reused in order to cancel a request.

requesting_device_id string

Required: ID of the device requesting the key.

RequestedKeyInfo
Name Type Description
algorithm string

Required: The encryption algorithm the requested key in this event is to be used with.

room_id string

Required: The room where the key is used.

sender_key string

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 for more information.

Changed in v1.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 for more information.

session_id string

Required: The ID of the session that the key is for.

Examples

{
  "content": {
    "action": "request_cancellation",
    "request_id": "1495474790150.19",
    "requesting_device_id": "RJYKSTBOIE"
  },
  "type": "m.room_key_request"
}
{
  "content": {
    "action": "request",
    "body": {
      "algorithm": "m.megolm.v1.aes-sha2",
      "room_id": "!Cuyf34gef24t:localhost",
      "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
      "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
    },
    "request_id": "1495474790150.19",
    "requesting_device_id": "RJYKSTBOIE"
  },
  "type": "m.room_key_request"
}

m.forwarded_room_key


This event type is used to forward keys for end-to-end encryption. It is encrypted as an m.room.encrypted event using Olm, then sent as a to-device event.

Event type: Message event

Content

Name Type Description
algorithm string

Required: The encryption algorithm the key in this event is to be used with.

forwarding_curve25519_key_chain [string]

Required: Chain of Curve25519 keys. It starts out empty, but each time the key is forwarded to another device, the previous sender in the chain is added to the end of the list. For example, if the key is forwarded from A to B to C, this field is empty between A and B, and contains A’s Curve25519 key between B and C.

room_id string

Required: The room where the key is used.

sender_claimed_ed25519_key string

Required: The Ed25519 key of the device which initiated the session originally. It is ‘claimed’ because the receiving device has no way to tell that the original room_key actually came from a device which owns the private part of this key unless they have done device verification.

sender_key string

Required: The Curve25519 key of the device which initiated the session originally.

session_id string

Required: The ID of the session that the key is for.

session_key string

Required: The key to be exchanged.

withheld object

Indicates that the key cannot be used to decrypt all the messages from the session because a portion of the session was withheld as described in Reporting that decryption keys are withheld. This object must include the code and reason properties from the m.room_key.withheld message that was received by the sender of this message.

Examples

{
  "content": {
    "algorithm": "m.megolm.v1.aes-sha2",
    "forwarding_curve25519_key_chain": [
      "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
    ],
    "room_id": "!Cuyf34gef24t:localhost",
    "sender_claimed_ed25519_key": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y",
    "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
    "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
    "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..."
  },
  "type": "m.forwarded_room_key"
}

m.dummy


This event type is used to indicate new Olm sessions for end-to-end encryption. Typically it is encrypted as an m.room.encrypted event, then sent as a to-device event.

The event does not have any content associated with it. The sending client is expected to send a key share request shortly after this message, causing the receiving client to process this m.dummy event as the most recent event and using the keyshare request to set up the session. The keyshare request and m.dummy combination should result in the original sending client receiving keys over the newly established session.

Event type: Message event

Content

Examples

{
  "content": {},
  "type": "m.dummy"
}
密钥管理 API

GET /_matrix/client/v3/keys/changes


Gets a list of users who have updated their device identity keys since a previous sync token.

The server should include in the results any users who:

  • currently share a room with the calling user (ie, both users have membership state join); and
  • added new device identity keys or removed an existing device with identity keys, between from and to.
Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
from string

Required: The desired start point of the list. Should be the next_batch field from a response to an earlier call to /sync. Users who have not uploaded new device identity keys since this point, nor deleted existing devices with identity keys since then, will be excluded from the results.

to string

Required: The desired end point of the list. Should be the next_batch field from a recent call to /sync - typically the most recent such call. This may be used by the server as a hint to check its caches are up to date.


Responses

Status Description
200 The list of users who updated their devices.

200 response

Name Type Description
changed [string]

The Matrix User IDs of all users who updated their device identity keys.

left [string]

The Matrix User IDs of all users who may have left all the end-to-end encrypted rooms they previously shared with the user.

{
  "changed": [
    "@alice:example.com",
    "@bob:example.org"
  ],
  "left": [
    "@clara:example.com",
    "@doug:example.org"
  ]
}

POST /_matrix/client/v3/keys/claim


Claims one-time keys for use in pre-key messages.

The request contains the user ID, device ID and algorithm name of the keys that are required. If a key matching these requirements can be found, the response contains it. The returned key is a one-time key if one is available, and otherwise a fallback key.

One-time keys are given out in the order that they were uploaded via /keys/upload. (All keys uploaded within a given call to /keys/upload are considered equivalent in this regard; no ordering is specified within them.)

Servers must ensure that each one-time key is returned at most once, so when a key has been returned, no other request will ever return the same key.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
one_time_keys {User ID: {string: string}}

Required: The keys to be claimed. A map from user ID, to a map from device ID to algorithm name.

timeout integer

The time (in milliseconds) to wait when downloading keys from remote servers. 10 seconds is the recommended default.

Request body example

{
  "one_time_keys": {
    "@alice:example.com": {
      "JLAFKJWSCS": "signed_curve25519"
    }
  },
  "timeout": 10000
}

Responses

Status Description
200 The claimed keys.

200 response

Name Type Description
failures {string: object}

If any remote homeservers could not be reached, they are recorded here. The names of the properties are the names of the unreachable servers.

If the homeserver could be reached, but the user or device was unknown, no failure is recorded. Instead, the corresponding user or device is missing from the one_time_keys result.

one_time_keys {User ID: {string: {string: string|KeyObject}}}

Required: One-time keys for the queried devices. A map from user ID, to a map from devices to a map from <algorithm>:<key_id> to the key object.

See the key algorithms section for information on the Key Object format.

If necessary, the claimed key might be a fallback key. Fallback keys are re-used by the server until replaced by the device.

KeyObject
Name Type Description
key string

Required: The key, encoded using unpadded base64.

signatures {User ID: object}

Required: Signature for the device. Mapped from user ID to signature object, containing mapping from key signing identifier to the signature (see also: Signing JSON)

{
  "one_time_keys": {
    "@alice:example.com": {
      "JLAFKJWSCS": {
        "signed_curve25519:AAAAHg": {
          "key": "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs",
          "signatures": {
            "@alice:example.com": {
              "ed25519:JLAFKJWSCS": "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw"
            }
          }
        }
      }
    }
  }
}

POST /_matrix/client/v3/keys/query


Returns the current devices and identity keys for the given users.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
device_keys {User ID: [string]}

Required: The keys to be downloaded. A map from user ID, to a list of device IDs, or to an empty list to indicate all devices for the corresponding user.

timeout integer

The time (in milliseconds) to wait when downloading keys from remote servers. 10 seconds is the recommended default.

Request body example

{
  "device_keys": {
    "@alice:example.com": []
  },
  "timeout": 10000
}

Responses

Status Description
200 The device information

200 response

Name Type Description
device_keys {User ID: {string: DeviceInformation}}

Information on the queried devices. A map from user ID, to a map from device ID to device information. For each device, the information returned will be the same as uploaded via /keys/upload, with the addition of an unsigned property.

failures {string: object}

If any remote homeservers could not be reached, they are recorded here. The names of the properties are the names of the unreachable servers.

If the homeserver could be reached, but the user or device was unknown, no failure is recorded. Instead, the corresponding user or device is missing from the device_keys result.

master_keys {User ID: CrossSigningKey}

Information on the master cross-signing keys of the queried users. A map from user ID, to master key information. For each key, the information returned will be the same as uploaded via /keys/device_signing/upload, along with the signatures uploaded via /keys/signatures/upload that the requesting user is allowed to see.

Added in v1.1

self_signing_keys {User ID: CrossSigningKey}

Information on the self-signing keys of the queried users. A map from user ID, to self-signing key information. For each key, the information returned will be the same as uploaded via /keys/device_signing/upload.

Added in v1.1

user_signing_keys {User ID: CrossSigningKey}

Information on the user-signing key of the user making the request, if they queried their own device information. A map from user ID, to user-signing key information. The information returned will be the same as uploaded via /keys/device_signing/upload.

DeviceInformation
Name Type Description
algorithms [string]

Required: The encryption algorithms supported by this device.

device_id string

Required: The ID of the device these keys belong to. Must match the device ID used when logging in.

keys {string: string}

Required: Public identity keys. The names of the properties should be in the format <algorithm>:<device_id>. The keys themselves should be encoded as specified by the key algorithm.

signatures {User ID: {string: string}}

Required: Signatures for the device key object. A map from user ID, to a map from <algorithm>:<device_id> to the signature.

The signature is calculated using the process described at Signing JSON.

unsigned UnsignedDeviceInfo

Additional data added to the device key information by intermediate servers, and not covered by the signatures.

user_id string

Required: The ID of the user the device belongs to. Must match the user ID used when logging in.

UnsignedDeviceInfo
Name Type Description
device_display_name string

The display name which the user set on the device.

CrossSigningKey
Name Type Description
keys {string: string}

Required: The public key. The object must have exactly one property, whose name is in the form <algorithm>:<unpadded_base64_public_key>, and whose value is the unpadded base64 public key.

signatures Signatures

Signatures of the key, calculated using the process described at Signing JSON. Optional for the master key. Other keys must be signed by the user's master key.

usage [string]

Required: What the key is used for.

user_id string

Required: The ID of the user the key belongs to.

{
  "device_keys": {
    "@alice:example.com": {
      "JLAFKJWSCS": {
        "algorithms": [
          "m.olm.v1.curve25519-aes-sha2",
          "m.megolm.v1.aes-sha2"
        ],
        "device_id": "JLAFKJWSCS",
        "keys": {
          "curve25519:JLAFKJWSCS": "3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI",
          "ed25519:JLAFKJWSCS": "lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI"
        },
        "signatures": {
          "@alice:example.com": {
            "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA"
          }
        },
        "unsigned": {
          "device_display_name": "Alice's mobile phone"
        },
        "user_id": "@alice:example.com"
      }
    }
  },
  "master_keys": {
    "@alice:example.com": {
      "keys": {
        "ed25519:base64+master+public+key": "base64+master+public+key"
      },
      "usage": [
        "master"
      ],
      "user_id": "@alice:example.com"
    }
  },
  "self_signing_keys": {
    "@alice:example.com": {
      "keys": {
        "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key"
      },
      "signatures": {
        "@alice:example.com": {
          "ed25519:base64+master+public+key": "signature+of+self+signing+key"
        }
      },
      "usage": [
        "self_signing"
      ],
      "user_id": "@alice:example.com"
    }
  },
  "user_signing_keys": {
    "@alice:example.com": {
      "keys": {
        "ed25519:base64+user+signing+public+key": "base64+user+signing+master+public+key"
      },
      "signatures": {
        "@alice:example.com": {
          "ed25519:base64+master+public+key": "signature+of+user+signing+key"
        }
      },
      "usage": [
        "user_signing"
      ],
      "user_id": "@alice:example.com"
    }
  }
}

POST /_matrix/client/v3/keys/upload


Publishes end-to-end encryption keys for the device.

Rate-limited: No
Requires authentication: Yes

Request

Request body

Name Type Description
device_keys DeviceKeys

Identity keys for the device. May be absent if no new identity keys are required.

fallback_keys {string: string|KeyObject}

The public key which should be used if the device’s one-time keys are exhausted. The fallback key is not deleted once used, but should be replaced when additional one-time keys are being uploaded. The server will notify the client of the fallback key being used through /sync.

There can only be at most one key per algorithm uploaded, and the server will only persist one key per algorithm.

When uploading a signed key, an additional fallback: true key should be included to denote that the key is a fallback key.

May be absent if a new fallback key is not required.

Added in v1.2

one_time_keys {string: string|KeyObject}

One-time public keys for “pre-key” messages. The names of the properties should be in the format <algorithm>:<key_id>. The format of the key is determined by the key algorithm.

May be absent if no new one-time keys are required.

DeviceKeys
Name Type Description
algorithms [string]

Required: The encryption algorithms supported by this device.

device_id string

Required: The ID of the device these keys belong to. Must match the device ID used when logging in.

keys {string: string}

Required: Public identity keys. The names of the properties should be in the format <algorithm>:<device_id>. The keys themselves should be encoded as specified by the key algorithm.

signatures {User ID: {string: string}}

Required: Signatures for the device key object. A map from user ID, to a map from <algorithm>:<device_id> to the signature.

The signature is calculated using the process described at Signing JSON.

user_id string

Required: The ID of the user the device belongs to. Must match the user ID used when logging in.

KeyObject
Name Type Description
key string

Required: The key, encoded using unpadded base64.

signatures {User ID: object}

Required: Signature for the device. Mapped from user ID to signature object, containing mapping from key signing identifier to the signature (see also: Signing JSON)

Request body example

{
  "device_keys": {
    "algorithms": [
      "m.olm.v1.curve25519-aes-sha2",
      "m.megolm.v1.aes-sha2"
    ],
    "device_id": "JLAFKJWSCS",
    "keys": {
      "curve25519:JLAFKJWSCS": "3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI",
      "ed25519:JLAFKJWSCS": "lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI"
    },
    "signatures": {
      "@alice:example.com": {
        "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA"
      }
    },
    "user_id": "@alice:example.com"
  },
  "fallback_keys": {
    "signed_curve25519:AAAAGj": {
      "fallback": true,
      "key": "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs",
      "signatures": {
        "@alice:example.com": {
          "ed25519:JLAFKJWSCS": "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw"
        }
      }
    }
  },
  "one_time_keys": {
    "signed_curve25519:AAAAHQ": {
      "key": "j3fR3HemM16M7CWhoI4Sk5ZsdmdfQHsKL1xuSft6MSw",
      "signatures": {
        "@alice:example.com": {
          "ed25519:JLAFKJWSCS": "IQeCEPb9HFk217cU9kw9EOiusC6kMIkoIRnbnfOh5Oc63S1ghgyjShBGpu34blQomoalCyXWyhaaT3MrLZYQAA"
        }
      }
    },
    "signed_curve25519:AAAAHg": {
      "key": "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs",
      "signatures": {
        "@alice:example.com": {
          "ed25519:JLAFKJWSCS": "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw"
        }
      }
    }
  }
}

Responses

Status Description
200 The provided keys were successfully uploaded.

200 response

Name Type Description
one_time_key_counts {string: integer}

Required: For each key algorithm, the number of unclaimed one-time keys of that type currently held on the server for this device. If an algorithm is not listed, the count for that algorithm is to be assumed zero.

{
  "one_time_key_counts": {
    "signed_curve25519": 20
  }
}
/sync 扩展

本模块为 /sync 响应新增可选 device_lists 字段(详见下文)。仅增量 /sync(指定 since 参数时)需返回。客户端应在初始同步后用 /keys/query/keys/changes 跟进,见跟踪用户设备列表

同时新增 device_one_time_keys_count 属性。注意拼写与 /keys/upload 响应的 one_time_key_counts 有区别。

[Added in v1.2] 最后,新增 device_unused_fallback_key_types 列举当前设备已上传但尚未被领用的备用密钥算法。若某算法此前上传的备用密钥不在列表,则应在必要时上传替换密钥。此属性为强制包含项,亦可用于判断服务器对备用密钥的支持(如 /versions 外的备用判断方式)。

参数 类型 描述
device_lists DeviceLists 可选。e2e 设备变更信息,仅在增量 sync 响应中出现。
device_one_time_keys_count {string: integer} 可选。按算法分列当前设备未被认领的一次性密钥数,未传视为 0。
device_unused_fallback_key_types [string] 必选。 未被使用的备用密钥算法列表。

DeviceLists

参数 类型 描述
changed [string] 设备身份或跨签名密钥有更新、或新近与本客户端共享加密房间的用户列表。
left [string] 自上次 sync 后,本客户端不再与之共享任何加密房间的用户列表。

最优逻辑下,仅在 Alice 更新设备、密钥或与 Bob 新建共享房间时,在 Bob 的 sync 的 changed 字段添加 Alice。但为了简化,服务器也可在 Alice 与 Bob 每次新建共享房间(无论是否已共享)时添加。

例:

{
  "next_batch": "s72595_4483_1934",
  "rooms": {"leave": {}, "join": {}, "invite": {}},
  "device_lists": {
    "changed": [
       "@alice:example.com",
    ],
    "left": [
       "@bob:example.com",
    ],
  },
  "device_one_time_keys_count": {
    "signed_curve25519": 20
  },
  "device_unused_fallback_key_types": ["signed_curve25519"]
}

报告密钥被拒绝

当客户端向房间内其他设备发送加密事件时,可选择通知那些因未提供密钥而无法解密事件的设备。如此接收方即可明确原因而非泛泛报错。

同理,一台设备通过密钥请求 向他设备请求密钥,对方亦可主动说明拒绝分享密钥。

如 Alice 一开始不愿向 Bob 分享部分消息的 Megolm 会话,后期决定给予 Bob 解密后续消息的权力,可发送只包含最新版会话密钥的消息,且在 Bob 的新设备请求密钥时,会获得被 ratchet(推进)过的最新版本。Bob 旧设备可在 m.forwarded_room_key 里以对象 withheld 字段附上最初被拒绝的原因代码。

m.room_key.withheld


This event type is used to indicate that the sender is not sharing room keys with the recipient. It is sent as a to-device event.

Possible values for code include:

  • m.blacklisted: the user/device was blacklisted.
  • m.unverified: the user/device was not verified, and the sender is only sharing keys with verified users/devices.
  • m.unauthorised: the user/device is not allowed to have the key. For example, this could be sent in response to a key request if the user/device was not in the room when the original message was sent.
  • m.unavailable: sent in reply to a key request if the device that the key is requested from does not have the requested key.
  • m.no_olm: an olm session could not be established.

In most cases, this event refers to a specific room key. The one exception to this is when the sender is unable to establish an olm session with the recipient. When this happens, multiple sessions will be affected. In order to avoid filling the recipient's device mailbox, the sender should only send one m.room_key.withheld message with no room_id nor session_id set. If the sender retries and fails to create an olm session again in the future, it should not send another m.room_key.withheld message with a code of m.no_olm, unless another olm session was previously established successfully. In response to receiving an m.room_key.withheld message with a code of m.no_olm, the recipient may start an olm session with the sender and send an m.dummy message to notify the sender of the new olm session. The recipient may assume that this m.room_key.withheld message applies to all encrypted room messages sent before it receives the message.

Event type: Message event

Content

Name Type Description
algorithm string

Required: The encryption algorithm for the key that this event is about.

One of: [m.megolm.v1.aes-sha2].

code string

Required: A machine-readable code for why the key was not sent. Codes beginning with m. are reserved for codes defined in the Matrix specification. Custom codes must use the Java package naming convention.

One of: [m.blacklisted, m.unverified, m.unauthorised, m.unavailable, m.no_olm].

reason string

A human-readable reason for why the key was not sent. The receiving client should only use this string if it does not understand the code.

room_id string

Required if code is not m.no_olm. The room for the key that this event is about.

sender_key string

Required: The unpadded base64-encoded device curve25519 key of the event's sender.

session_id string

Required if code is not m.no_olm. The session ID of the key that this event is about.

Examples

{
  "content": {
    "algorithm": "m.megolm.v1.aes-sha2",
    "code": "m.unverified",
    "reason": "Device not verified",
    "room_id": "!Cuyf34gef24t:localhost",
    "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
    "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
  },
  "type": "m.room_key.withheld"
}

机密信息

[Added in v1.1]

客户端可能拥有希望授权给其他客户端访问但不希望服务器知晓的机密信息,因此这些信息在通过服务器传递时必须进行加密。这可以通过异步方式(将加密后的数据存储在服务器供之后获取)或同步方式(客户端之间互发消息)来实现。

每个机密信息都有一个标识符,客户端在存储、获取、请求或共享机密信息时会通过该标识符进行引用。机密信息是普通字符串;如需存储结构化数据,可将其编码为字符串形式。

本节所描述的机制被称为“安全机密信息存储与共享”(secure secret storage and sharing)、简称“SSSS”或“4S”。

存储

当机密信息存储在服务器上时,会以账户数据的形式存储在用户的账户数据中,事件类型等于机密信息的标识符。用于加密机密信息的密钥,其描述也会存储在用户的账户数据中。用户可以拥有多个密钥,从而根据分配给客户端的密钥控制其可访问哪些机密信息。

密钥存储

每个密钥都有一个 ID,其描述以事件类型 m.secret_storage.key.[key ID] 存储在用户的账户数据中。密钥的账户数据内容包含一个 algorithm 属性,表示所用加密算法,以及一个 name 属性,为该密钥的可读名称。密钥描述中还可以包含一个 passphrase 属性,该属性用于根据用户输入的口令生成密钥,详见从口令派生密钥

KeyDescription

参数 类型 说明
name string 可选。密钥名称。如果未提供,客户端可使用“未命名密钥”之类的通用名称;若该密钥被标记为默认密钥(见下文),则可用“默认密钥”。
algorithm string 必需。 此密钥使用的加密算法。目前仅支持 m.secret_storage.v1.aes-hmac-sha2
passphrase string 详见从口令派生密钥一节。

其他属性依赖于加密算法,详见下文。

如需将某个密钥标记为“默认”密钥,应在用户的账户数据中,设置事件类型为 m.secret_storage.default_key 的对象,其 key 属性为该密钥 ID。默认密钥将用于加密用户期望在所有客户端均可用的所有机密信息。除非用户另行指定,客户端将尝试使用默认密钥解密机密信息。

希望为用户提供简化界面的客户端可只支持默认密钥。若未指定默认密钥,客户端可视为不存在任何密钥。当此类客户端创建密钥时,应将其标为默认密钥。

DefaultKey

参数 类型 说明
key string 必需。 默认密钥的ID。
m.secret_storage.v1.aes-hmac-sha2

为便于客户端检查用户输入密钥的正确性,m.secret_storage.v1.aes-hmac-sha2 算法使用的密钥会存储附加数据。

存储密钥时,客户端应:

  1. 以机密信息存储密钥为基础,使用 SHA-256 为哈希值,32字节0为salt,空字符串为info执行 HKDF,生成64字节数据。前32字节为AES密钥,后32字节为MAC密钥。

  2. 生成16字节随机数,将第63位设为0(为兼容不同 AES-CTR 实现),作为AES初始化向量(IV)。

  3. 用第1步所得的AES密钥和IV,以 AES-CTR-256 加密32字节的零组成的消息。

  4. 用第1步所得的MAC密钥,对第3步所得的原始加密数据执行 HMAC-SHA-256。

  5. 将第2步生成的IV与第4步生成的 MAC,使用无填充 base64 编码,并分别存储在 ivmac 属性中,属性位置为 m.secret_storage.key.[key ID] 账户数据。(第3步得到的密文仅用于MAC计算后即丢弃。)

客户端在检查密钥正确性时可重复此过程:若MAC值匹配,则密钥正确。但需注意,这些属性为可选。若不存在此类属性,客户端必须假定密钥有效。

还需注意,虽然建议客户端应当如上采用无填充base64进行编码,但部分现有实现使用标准RFC4648规范base64并含有填充,因此客户端必须同时兼容两种编码。

因此,面向该算法的 m.secret_storage.key.[key ID] 账户数据结构如下:

AesHmacSha2KeyDescription

参数 类型 说明
name string 可选。密钥名称。
algorithm string 必需。 此密钥使用的加密算法:m.secret_storage.v1.aes-hmac-sha2
passphrase object 详见从口令派生密钥一节。
iv string 可选。校验用的16字节初始化向量,base64编码。
mac string 可选。对32字节零加密结果的MAC,base64编码。

示例:

{
  "name": "m.default",
  "algorithm": "m.secret_storage.v1.aes-hmac-sha2",
  "iv": "random+data",
  "mac": "mac+of+encrypted+zeros"
}
机密信息存储

加密后的数据以具体功能定义的事件类型,存储在用户账户数据中。账户数据会有一个 encrypted 属性,为从密钥ID到对象的映射。特定密钥的 m.secret_storage.key.[key ID] 数据中的算法定义了解释其他属性的方式,但大多数加密方案应包含 ciphertextmac 两个属性,其中 ciphertext 属性为无填充base64编码的密文,mac 用于保证数据完整性。

Secret

参数 类型 说明
encrypted {string: object} 必需。 密钥ID到加密数据的映射。加密数据的确切格式取决于密钥算法。参见m.secret_storage.v1.aes-hmac-sha2 节中的 AesHmacSha2EncryptedData 定义。

示例:

某机密信息使用 ID 为 key_id_1key_id_2 的密钥加密:

org.example.some.secret:

{
  "encrypted": {
    "key_id_1": {
      "ciphertext": "base64+encoded+encrypted+data",
      "mac": "base64+encoded+mac",
      // ... 其他属性,见 m.secret_storage.key.key_id_1 的 algorithm 属性
    },
    "key_id_2": {
      // ...
    }
  }
}

相应密钥的描述:

m.secret_storage.key.key_id_1:

{
  "name": "Some key",
  "algorithm": "m.secret_storage.v1.aes-hmac-sha2",
  // ... 其他属性,见 algorithm
}

m.secret_storage.key.key_id_2:

{
  "name": "Some other key",
  "algorithm": "m.secret_storage.v1.aes-hmac-sha2",
  // ... 其他属性,见 algorithm
}

key_id_1 为默认密钥,则还应有:

m.secret_storage.default_key:

{
  "key": "key_id_1"
}
m.secret_storage.v1.aes-hmac-sha2

采用 m.secret_storage.v1.aes-hmac-sha2 算法加密的机密信息,使用 AES-CTR-256 进行加密,并用 HMAC-SHA-256 进行认证,加密过程如下:

  1. 以机密信息存储密钥为基础,使用 SHA-256 作为哈希,32字节0为salt,以机密名称为info,执行HKDF生成64字节。前32字节为AES密钥,后32字节为MAC密钥。

  2. 生成16字节随机数,将第63位设为0(为兼容不同AES-CTR实现),用作AES初始化向量(IV)。

  3. 用第1步获得的AES密钥和IV,采用 AES-CTR-256 加密数据。

  4. 用第1步获得的MAC密钥,对第3步获得的原始加密数据执行HMAC-SHA-256。

  5. 将第2步的 IV、第3步的密文和第4步的 MAC 用无填充 base64 编码,分别存为账户数据对象的 ivciphertextmac 属性。

    注意:部分现有实现使用标准RFC4648规范base64带填充进行编码,因此客户端必须两种编码均可接受。

采用该算法加密的账户数据对象的 encrypted 属性结构如下:

AesHmacSha2EncryptedData

参数 类型 说明
iv string 必需。 16字节初始化向量,base64编码。
ciphertext string 必需。 AES-CTR加密的数据,base64编码。
mac string 必需。 MAC,base64编码。

示例,加密后数据形态如下:

{
  "encrypted": {
    "key_id": {
      "iv": "16+bytes+base64",
      "ciphertext": "base64+encoded+encrypted+data",
      "mac": "base64+encoded+mac"
    }
  }
}
密钥表示

用户获得 m.secret_storage.v1.aes-hmac-sha2 的原始密钥时,应以通用加密密钥表示方法的字符串形式呈现密钥。

从口令派生密钥

用户可能希望使用自选口令而非随机生成的密钥。在这种情况下,如何从口令生成密钥的信息会保存在 m.secret_storage.key.[key ID] 账户数据的 passphrase 属性中。passphrase 属性包含一个 algorithm 属性,表示如何据口令生成密钥。passphrase 的其他属性由指定的算法定义。

当前只定义了 m.pbkdf2 算法。对于 m.pbkdf2passphrase 属性包括:

参数 类型 说明
algorithm string 必需。 必须为 m.pbkdf2
salt string 必需。 PBKDF2 算法使用的 salt。
iterations integer 必需。 PBKDF2 算法使用的迭代次数。
bits integer 可选。生成密钥的位数,默认256。

密钥将使用 PBKDF2 算法,以 SHA-512 为哈希,使用 salt 属性作为盐值,iterations 属性指明迭代次数生成。

示例:

{
    "passphrase": {
        "algorithm": "m.pbkdf2",
        "salt": "MmMsAlty",
        "iterations": 100000,
        "bits": 256
    },
    ...
}

共享

客户端如需向其他设备请求机密信息,可发送 m.secret.request 设备事件,action 设为 requestname 设为机密信息标识符。有意愿分享机密信息的设备将用Olm加密,发送 m.secret.send 事件回复。当原始客户端获取到机密信息后,应向所有除获得机密信息那台设备外的其他设备发送 m.secret.request 事件,action 设置为 request_cancellation。客户端应忽略未针对本机发送 m.secret.request 事件的设备所收到的 m.secret.send 事件。

客户端必须确保仅将机密信息共享给被授权查看的其他设备。例如,客户端应仅与自己已验证的设备共享机密信息,必要时还可提示用户确认共享操作。

事件定义

m.secret.request


Sent by a client to request a secret from another device or to cancel a previous request. It is sent as an unencrypted to-device event.

Event type: Message event

Content

Name Type Description
action string

Required:

One of: [request, request_cancellation].

name string

Required if action is request. The name of the secret that is being requested.

request_id string

Required: A random string uniquely identifying (with respect to the requester and the target) the target for a secret. If the secret is requested from multiple devices at the same time, the same ID MAY be used for every target. The same ID is also used in order to cancel a previous request.

requesting_device_id string

Required: The ID of the device requesting the secret.

Examples

{
  "content": {
    "action": "request",
    "name": "org.example.some.secret",
    "request_id": "randomly_generated_id_9573",
    "requesting_device_id": "ABCDEFG"
  },
  "type": "m.secret.request"
}

m.secret.send


Sent by a client to share a secret with another device, in response to an m.secret.request event. It must be encrypted as an m.room.encrypted event using Olm, then sent as a to-device event.

The request_id must match the ID previously given in an m.secret.request event. The recipient must ensure that this event comes from a device that the m.secret.request event was originally sent to, and that the device is a verified device owned by the recipient. This should be done by checking the sender key of the Olm session that the event was sent over.

Event type: Message event

Content

Name Type Description
request_id string

Required: The ID of the request that this is a response to.

secret string

Required: The contents of the secret

Examples

{
  "content": {
    "request_id": "randomly_generated_id_9573",
    "secret": "ThisIsASecretDon'tTellAnyone"
  },
  "type": "m.secret.send"
}

房间历史可见性

该模块增加了对控制房间中过往事件可见性的支持。

world_readable 外,在所有情况下,用户都必须先加入房间才能查看该房间内的事件。一旦用户加入房间,他们将能访问该房间中某个事件子集。该子集如何选择由下文描述的 m.room.history_visibility 事件控制。用户离开房间后,仍可查看离开前被允许查看的事件,但无法查看离开后收到的事件。

m.room.history_visibility 事件有四个选项:

  • world_readable - 只要此项为 m.room.history_visibility 的值,任何参与的服务器都可以与任何人共享所有事件,无论其是否曾加入该房间。
  • shared - 以前的事件始终对新加入的成员可见。即使用户不在房间内时发送的事件,房间内的所有事件也都可访问。
  • invited - 新加入成员仅能访问自被邀请起的事件。当成员的状态变为非 invitejoin 时,事件将不再可访问。
  • joined - 新加入成员仅能访问自加入该房间起的事件。当成员的状态变为非 join 时,事件将不再可访问。

这些选项应用于事件发送时。判断依据是事件被添加到 DAG 时 m.room.history_visibility 的状态。这意味着,若当时的设置更为严格,客户端不能事后选择向新用户显示或隐藏历史记录。

事件

m.room.history_visibility


This event controls whether a user can see the events that happened in a room from before they joined.

Event type: State event
State key A zero-length string.

Content

Name Type Description
history_visibility string

Required: Who can see the room history.

One of: [invited, joined, shared, world_readable].

Examples

{
  "content": {
    "history_visibility": "shared"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.history_visibility",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

若历史可见性设置为 world_readable,客户端可提示用户,非房间成员也可能读取事件内容。

服务器行为

默认情况下,如果未设置 history_visibility,或其值无效,则视为 shared。关于用户能否查看某个事件,需依据该事件发生时房间的状态判定。

  1. 如果 history_visibility 被设置为 world_readable,允许查看。
  2. 如果用户的 membershipjoin,允许查看。
  3. 如果 history_visibilityshared,且用户在事件发送后曾加入过房间,允许查看。
  4. 如果用户的 membershipinvite,且 history_visibility 被设置为 invited,允许查看。
  5. 否则,拒绝访问。

针对 m.room.history_visibility 事件本身,如果事件之前或之后history_visibility 允许用户可见,则应允许该用户查看。例如,即使用户不是房间成员,也应可以看到将 history_visibilityworld_readable 更改为 joined 或从 joined 更改为 world_readablem.room.history_visibility 事件。

同样,对于用户自身的 m.room.member 事件,如果事件前后membership 有任一允许用户查看,则应允许该用户查看该事件。例如,用户始终可以看到将其 membership 设为 join 的事件,或将其从 join 更改为其他值的事件,即使 history_visibilityjoined

安全注意事项

出于兼容性考虑,history_visibility 默认值为 shared。客户端需注意,若未设置该事件,则其房间历史对所有成员均可见。

推送通知

                                   +--------------------+  +-------------------+
                  Matrix HTTP      |                    |  |                   |
             Notification Protocol |   应用开发者        |  |   设备厂商         |
                                   |                    |  |                   |
           +-------------------+   | +----------------+ |  | +---------------+ |
           |                   |   | |                | |  | |               | |
           | Matrix 主服务器   +-----> 推送网关(Gateway)+------> 推送供应商      | |
           |                   |   | |                | |  | |               | |
           +-^-----------------+   | +----------------+ |  | +----+----------+ |
             |                     |                    |  |      |            |
    Matrix   |                     |                    |  |      |            |
 客户端/服务器API +                |                    |  |      |            |
             |      |              +--------------------+  +-------------------+
             |   +--+-+                                           |
             |   |    <-------------------------------------------+
             +---+    |
                 |    |          供应商推送协议
                 +----+
          移动设备或客户端

本模块增加了对推送通知的支持。主服务器会将事件的通知发送到用户配置的 HTTP 端点。用户也可以自定义多条规则,决定哪些事件会生成通知。这些规则全部存储并由用户的主服务器管理。这允许用户专属的推送设置在不同客户端应用之间复用。

上述图示显示了推送通知发送到手机时的流程,通知通过手机厂商(例如 Apple 的 APNS 或 Google 的 GCM)进行提交。具体流程如下:

  1. 客户端应用登录到主服务器。
  2. 客户端应用在其厂商的推送供应商处注册,并获得某种路由令牌。
  3. 移动应用通过客户端/服务器 API 添加一个“推送者(pusher)”,并提供为该应用配置的特定推送网关的 URL,同时提供从推送供应商获得的路由令牌。
  4. 主服务器使用提供的 URL 向推送网关发送 HTTP 请求。推送网关将该通知中继给推送供应商,并附带发送推送通知所需的路由令牌及相关私密凭证。
  5. 推送供应商将通知发送至设备。

本节相关术语定义如下:

推送供应商(Push Provider)

推送供应商是由设备厂商管理的服务,可以直接将通知发送到设备。例如 Google Cloud Messaging(GCM)和 Apple Push Notification Service(APNS)都是推送供应商的例子。

推送网关(Push Gateway)

推送网关是接收主服务器 HTTP 事件通知并将其转发给其他协议(如 iOS 设备的 APNS 或 Android 设备的 GCM)的服务器。客户端在设置 Pusher 时,会告知主服务器该将通知发送至哪个推送网关。

推送者(Pusher)

Pusher 是主服务器上负责管理并发送 HTTP 通知给用户的工作进程。每个用户可以有多个 pusher,每组装置对应一个。

推送规则(Push Rule)

推送规则是一条声明了在什么条件下事件会被发送到推送网关,以及通知应该如何呈现的规则。这些规则储存在用户的主服务器上。用户可通过客户端/服务器 API 手动配置、创建与查看这些规则。

推送规则集(Push Ruleset)

推送规则集根据某些标准限定某组规则的作用范围。比如,某些规则只针对来自特定发信人的消息、特定聊天室、或作为默认规则。推送规则集包含了全部作用域与规则集合。

推送规则

推送规则是一条声明了在什么条件下事件会被发送到推送网关,以及通知该如何呈现的规则。推送规则有多种“类型(kind)”,每条规则都有相应的优先级。每条推送规则必须包含 kindrule_idrule_id 是在该类型和作用域内部唯一的字符串:同种类型但属于不同设备的规则之间,rule_id 并不要求全局唯一。依据 kind 类型,规则可以具有额外的键。

不同的 kind 类型按如下顺序检查:

  1. Override 规则 (override)。 最高优先级的规则,由用户配置作为覆盖项。

  2. 内容专属规则 (content)。 针对匹配某些模式的消息配置行为。内容规则包含一个参数 —— pattern,提供待匹配的glob 风格模式。 该匹配大小写不敏感,必须匹配消息内容的 content.body 属性中任何以单词边界起止的子串。单词边界指文本的起始或结尾,或者非 [A-Z], [a-z], [0-9], _ 集合中的任意字符。大小写不敏感的具体实现由主服务器定义。

  3. 房间专属规则 (room)。 更改某个房间内所有消息的通知行为。房间规则的 rule_id 总为其作用房间的 ID。

  4. 发信人专属规则 (sender)。 针对某个 Matrix 用户 ID 发出的消息配置通知行为。发信人规则的 rule_id 总为该用户的 Matrix ID。

  5. Underride 规则 (underride)。override 规则作用相同,但其优先级低于 contentroomsender 规则。

同一 kind 的规则可以指定顺序优先级,用于确定在多条规则命中时选择哪一条。例如,规则 A 匹配“tea”,规则 B 匹配“time”,则消息 “It’s time for tea” 会被两条规则匹配,随后按顺序决定实际生效的规则。只有优先级最高的规则的 actions 会被发送给推送网关。

每条规则可以启用或禁用。被禁用的规则永不匹配。如果没有任何规则匹配某事件,主服务器不得为该事件通知推送网关。主服务器也不得为用户自己发送的事件通知推送网关。

动作(Actions)

所有规则都有一个关联的 actions 动作列表。动作决定对于匹配的事件,通知是否被送达及如何送达。定义如下:

notify

为每个匹配事件产生推送通知。

set_tweak

设置发送通知请求给推送网关时 tweaks 字典键中的一项。格式为字典对象,set_tweak 为要设置的调整项名,如果需要还可带有 value 指定其值。

已定义以下调整项:

sound

字符串,表示此通知到达时播放的声音。default 表示播放默认提示音。设备也可根据实际选择如振动等其他告警方式。

highlight

布尔值,是否应在界面中高亮展示这条消息。通常会以不同颜色/样式突出消息,或调整 UI 以特别提示发生消息的房间。如果给定了没有显式值的 highlight 调整项,其值视为 true。若未指定则为 false

调整项会透明地通过主服务器传递,客户端应用与推送网关可约定自定义调整项。例如,可指定在移动设备上如何闪烁通知灯。

无参数的动作用字符串表示,否则用以动作名为键、相关参数为其他键的字典表示,例如:{ "set_tweak": "sound", "value": "default" }

历史动作说明

早期 Matrix 规范包含 dont_notifycoalesce 动作。客户端和主服务器必须忽略这些动作,比如遇到时应从动作数组中剔除。因此,包含 ["dont_notify"] 的规则应等效于动作数组为空的规则。

条件(Conditions)

overrideunderride 规则可以有“条件”列表。事件必须满足所有条件,该规则才会匹配。若规则无任何条件,则总是匹配。

无法识别的条件不得匹配任何事件,相当于禁用该规则。

roomsendercontent 规则不以条件列表的方式定义,而是有预定义条件。房间和发信人规则中,rule_id 的内容决定其行为。

以下条件类型已定义:

event_match

对事件某属性用 glob 模式匹配。参数:

匹配大小写不敏感,必须匹配 key 指定属性的整个值(但 content.body 见下文)。大小写不敏感的实现由主服务器定义。

如事件中 key 指定属性完全不存在或不是字符串,即便 pattern*,条件也不匹配。

例如,若 keycontent.topicpatternlunc?*,其事件如下将会匹配:

{
  "content": {
    "topic": "Lunch plans",
  },
  "event_id": "$143273582443PhrSn:example.org",
  "room_id": "!636q39766251:example.com",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.topic"
}

其它能匹配的 topic 值有:

  • "LUNCH"(大小写不敏感,* 可匹配零个字符)

以下 topic 不匹配:

  • " lunch"(前导空格)
  • "lunc"? 必须匹配一个字符)
  • null(不是字符串)

特殊情况:若 keycontent.bodypattern 必须匹配属性值任一单词边界起止的子串。单词边界指值的起止或非 [A-Z][a-z][0-9]_ 集合的字符。

例如,key 若为 content.bodypatternex*ple,则如下消息会匹配:

{
  "content": {
    "body": "An example event."
  },
  "event_id": "$143273976499sgjks:example.org",
  "room_id": "!636q39766251:example.com",
  "sender": "@example:example.org",
  "type": "m.room.message"
}

其它匹配 body 值有:

  • "exple"(模式可匹配 body 起止)
  • "An exciting triple-whammy"(模式可跨多单词,且 - 被视为分隔符)

注意,state_key 没有默认隐式条件。即,针对只匹配状态事件的推送规则,必须明确指定对 state_key 的条件。

例如,见下方默认规则 .m.rule.tombstone

event_property_is

对事件属性值进行精确匹配。参数:

  • key:事件属性的点分路径,如 content.body
  • value:要匹配的值。

匹配为精确等值,仅支持非复合(canonical JSON)类型:字符串、区间 [-(2**53)+1, (2**53)-1] 内的整数、布尔值和 null

key 指定属性不存在,或类型不是字符串、整数、布尔或 null,条件不匹配。

例如,若 keycontent.m\.federatevaluetrue,事件如下匹配:

{
  "content": {
    "creator": "@example:example.org",
    "m.federate": true,
    "predecessor": {
      "event_id": "$something:example.org",
      "room_id": "!oldroom:example.org"
    },
    "room_version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "room_id": "!636q39766251:example.com",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.create"
}

下列 m.federate 值不匹配:

  • "true"(类型不同,字符串)
  • 1(不进行类型转换)

event_property_contains

如事件某数组属性精确包含特定值则匹配。参数:

  • key:事件属性的点分路径,如 content.body

  • value:要匹配的值。

仅当数组元素为非复合 canonical JSON 类型(字符串、上述区间内整数、布尔、null)时有效。其他类型将被忽略。

key 指定属性不存在,或不是数组,则条件不匹配。

例如,若 keycontent.alt_aliasesvalue"#myroom:example.com",如下事件会匹配:

{
  "content": {
    "alias": "#somewhere:localhost",
    "alt_aliases": [
      "#somewhere:example.org",
      "#myroom:example.com"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.canonical_alias",
  "unsigned": {
    "age": 1234
  }
}

下列 alt_aliases 值不匹配:

  • ":example.com"(部分匹配不通过)

contains_display_name

匹配 content.body 含有房间内该用户当前显示昵称的消息。因显示昵称可能变化,维护对应规则较难,故单独为此设一条件。该条件无参数。

room_member_count

匹配房间当前成员数。参数:

  • is:一个支持可选前缀的十进制整数,前缀包括 ==<>>=<= 。如 < 匹配成员数小于给定数字,依此类推。缺省无前缀时为 ==

sender_notification_permission

结合房内当前权限设置,确保事件发送者权限足够以触发通知。

参数:

  • key:字符串,指定需触发何种类型通知时发信人需具备的权限级别,如 room。详见 m.room.power_levels 事件结构。该 key 用于根据 power level 对象内容查找通知类型对应权限级别。

预定义规则

主服务器可指定“服务器默认规则”。该类规则优先级低于“用户自定义规则”,唯一例外是 .m.rule.master,它总是所有规则中最高的。所有服务器默认规则的 rule_id 必须以点(”.")开头以便区分。以下为规定的服务器默认规则:

默认 Override 规则

.m.rule.master

匹配所有事件。启用后可关闭所有推送通知。不同于其它服务器默认规则,此规则始终优先级最高,连用户自定义规则都排在其后。默认禁用。

定义:

{
    "rule_id": ".m.rule.master",
    "default": true,
    "enabled": false,
    "conditions": [],
    "actions": []
}

.m.rule.suppress_notices

匹配 msgtypenotice 的消息。

定义:

{
    "rule_id": ".m.rule.suppress_notices",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_match",
            "key": "content.msgtype",
            "pattern": "m.notice"
        }
    ],
    "actions": []
}

.m.rule.invite_for_me

匹配针对该用户的新房间邀请。

定义:

{
    "rule_id": ".m.rule.invite_for_me",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.room.member"
        },
        {
            "key": "content.membership",
            "kind": "event_match",
            "pattern": "invite"
        },
        {
            "key": "state_key",
            "kind": "event_match",
            "pattern": "[the user's Matrix ID]"
        }
    ],
    "actions": [
       "notify",
        {
            "set_tweak": "sound",
            "value": "default"
        }
    ]
}

.m.rule.member_event

匹配任意 m.room.member_event

定义:

{
    "rule_id": ".m.rule.member_event",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.room.member"
        }
    ],
    "actions": []
}

.m.rule.is_user_mention

[Added in v1.7]

匹配在 m.mentions 属性下 user_ids 包含用户 Matrix ID 的任意消息。

定义:

{
    "rule_id": ".m.rule.is_user_mention",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_property_contains",
            "key": "content.m\\.mentions.user_ids",
            "value": "[the user's Matrix ID]"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "sound",
            "value": "default"
        },
        {
            "set_tweak": "highlight"
        }
    ]
}

.m.rule.contains_display_name

[Changed in v1.7]

v1.7 起,该规则已废弃,仅在事件未含 m.mentions 属性 时启用

匹配内容含有用户当前房间显示昵称的消息。

定义:

{
    "rule_id": ".m.rule.contains_display_name",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "contains_display_name"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "sound",
            "value": "default"
        },
        {
            "set_tweak": "highlight"
        }
    ]
}

.m.rule.is_room_mention

[Added in v1.7]

匹配拥有相应权限、m.mentions 属性中的 room 字段为 true 的发信人消息。

定义:

{
    "rule_id": ".m.rule.is_room_mention",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_property_is",
            "key": "content.m\\.mentions.room",
            "value": true
        },
        {
            "kind": "sender_notification_permission",
            "key": "room"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "highlight"
        }
    ]
}

.m.rule.roomnotif

[Changed in v1.7]

自 v1.7 起,该规则已废弃,仅在事件未含 m.mentions 属性 时启用

匹配拥有权限且内容含有 @room 字符串(需全房通知)的消息。

定义:

{
    "rule_id": ".m.rule.roomnotif",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_match",
            "key": "content.body",
            "pattern": "@room"
        },
        {
            "kind": "sender_notification_permission",
            "key": "room"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "highlight"
        }
    ]
}

.m.rule.tombstone

匹配所有类型为 m.room.tombstone 的状态事件。用于通知房间升级,效果类似于 @room 通知。

定义:

{
    "rule_id": ".m.rule.tombstone",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_match",
            "key": "type",
            "pattern": "m.room.tombstone"
        },
        {
            "kind": "event_match",
            "key": "state_key",
            "pattern": ""
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "highlight"
        }
    ]
}

.m.rule.reaction

[Added in v1.7]

匹配所有类型为 m.reaction 的事件。用于抑制 m.reaction 事件的通知。

定义:

{
    "rule_id": ".m.rule.reaction",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_match",
            "key": "type",
            "pattern": "m.reaction"
        }
    ],
    "actions": []
}

.m.rule.room.server_acl

[Added in v1.4]

抑制对 m.room.server_acl 事件的通知。

定义:

{
    "rule_id": ".m.rule.room.server_acl",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_match",
            "key": "type",
            "pattern": "m.room.server_acl"
        },
        {
            "kind": "event_match",
            "key": "state_key",
            "pattern": ""
        }
    ],
    "actions": []
}

.m.rule.suppress_edits

[Added in v1.9]

抑制与事件替换相关的通知。

定义:

{
    "rule_id": ".m.rule.suppress_edits",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "event_property_is",
            "key": "content.m\\.relates_to.rel_type",
            "value": "m.replace"
        }
    ],
    "actions": []
}
默认 Content 规则

.m.rule.contains_user_name

[Changed in v1.7]

自 v1.7 起,该规则已废弃,仅当事件无 m.mentions 属性 时启用

匹配内容包含用户 Matrix ID 本地部分(以单词边界分隔)的消息。

定义(作为 content 规则):

{
    "rule_id": ".m.rule.contains_user_name",
    "default": true,
    "enabled": true,
    "pattern": "[the local part of the user's Matrix ID]",
    "actions": [
        "notify",
        {
            "set_tweak": "sound",
            "value": "default"
        },
        {
            "set_tweak": "highlight"
        }
    ]
}
默认 Underride 规则

.m.rule.call

匹配所有传入 VOIP 呼叫事件。

定义:

{
    "rule_id": ".m.rule.call",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.call.invite"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "sound",
            "value": "ring"
        }
    ]
}

.m.rule.encrypted_room_one_to_one

匹配发送至仅有两名成员的加密房间内的任意加密事件。不同于普通推送规则,加密后事件无法基于内容匹配,故此规则表现为“全匹配”或“不匹配” —— 若为 1:1 房间内所有加密事件都匹配,否则全不匹配。

定义:

{
    "rule_id": ".m.rule.encrypted_room_one_to_one",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "room_member_count",
            "is": "2"
        },
        {
            "kind": "event_match",
            "key": "type",
            "pattern": "m.room.encrypted"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "sound",
            "value": "default"
        }
    ]
}

.m.rule.room_one_to_one

匹配仅有两名成员的房间内任意消息。

定义:

{
    "rule_id": ".m.rule.room_one_to_one",
    "default": true,
    "enabled": true,
    "conditions": [
        {
            "kind": "room_member_count",
            "is": "2"
        },
        {
            "kind": "event_match",
            "key": "type",
            "pattern": "m.room.message"
        }
    ],
    "actions": [
        "notify",
        {
            "set_tweak": "sound",
            "value": "default"
        }
    ]
}

.m.rule.message

匹配所有聊天消息。

定义:

{
     "rule_id": ".m.rule.message",
     "default": true,
     "enabled": true,
     "conditions": [
         {
             "kind": "event_match",
             "key": "type",
             "pattern": "m.room.message"
         }
     ],
     "actions": [
         "notify"
     ]
}

.m.rule.encrypted

匹配所有加密事件。由于加密,事件内容不能被常规匹配,本规则表现为组房内所有加密事件全匹配或全不匹配。

定义:

{
     "rule_id": ".m.rule.encrypted",
     "default": true,
     "enabled": true,
     "conditions": [
         {
             "kind": "event_match",
             "key": "type",
             "pattern": "m.room.encrypted"
         }
     ],
     "actions": [
         "notify"
     ]
}

推送规则:API

客户端可通过以下 API 全局或针对各设备获取、添加、修改、删除推送规则。

GET /_matrix/client/v3/pushrules/


Retrieve all push rulesets for this user. Currently the only push ruleset defined is global.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 All the push rulesets for this user.

200 response

Name Type Description
global Ruleset

Required: The global ruleset.

Ruleset
Name Type Description
content [PushRule]
override [PushRule]
room [PushRule]
sender [PushRule]
underride [PushRule]
PushRule
Name Type Description
actions [string|object]

Required: The actions to perform when this rule is matched.

conditions [PushCondition]

The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Only applicable to underride and override rules.

default boolean

Required: Whether this is a default rule, or has been set explicitly.

enabled boolean

Required: Whether the push rule is enabled or not.

pattern string

The glob-style pattern to match against. Only applicable to content rules.

rule_id string

Required: The ID of this rule.

PushCondition
Name Type Description
is string

Required for room_member_count conditions. A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.

key string

Required for event_match, event_property_is and event_property_contains conditions. The dot-separated field of the event to match.

Required for sender_notification_permission conditions. The field in the power level event the user needs a minimum power level for. Fields must be specified under the notifications property in the power level event’s content.

kind string

Required: The kind of condition to apply. See conditions for more information on the allowed kinds and how they work.

pattern string

Required for event_match conditions. The glob-style pattern to match against.

value string|integer|boolean|null

Required for event_property_is and event_property_contains conditions. A non-compound canonical JSON value to match against.

{
  "global": {
    "content": [
      {
        "actions": [
          "notify",
          {
            "set_tweak": "sound",
            "value": "default"
          },
          {
            "set_tweak": "highlight"
          }
        ],
        "default": true,
        "enabled": true,
        "pattern": "alice",
        "rule_id": ".m.rule.contains_user_name"
      }
    ],
    "override": [
      {
        "actions": [],
        "conditions": [],
        "default": true,
        "enabled": false,
        "rule_id": ".m.rule.master"
      },
      {
        "actions": [],
        "conditions": [
          {
            "key": "content.msgtype",
            "kind": "event_match",
            "pattern": "m.notice"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.suppress_notices"
      }
    ],
    "room": [],
    "sender": [],
    "underride": [
      {
        "actions": [
          "notify",
          {
            "set_tweak": "sound",
            "value": "ring"
          },
          {
            "set_tweak": "highlight",
            "value": false
          }
        ],
        "conditions": [
          {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.call.invite"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.call"
      },
      {
        "actions": [
          "notify",
          {
            "set_tweak": "sound",
            "value": "default"
          },
          {
            "set_tweak": "highlight"
          }
        ],
        "conditions": [
          {
            "kind": "contains_display_name"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.contains_display_name"
      },
      {
        "actions": [
          "notify",
          {
            "set_tweak": "sound",
            "value": "default"
          },
          {
            "set_tweak": "highlight",
            "value": false
          }
        ],
        "conditions": [
          {
            "is": "2",
            "kind": "room_member_count"
          },
          {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.room.message"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.room_one_to_one"
      },
      {
        "actions": [
          "notify",
          {
            "set_tweak": "sound",
            "value": "default"
          },
          {
            "set_tweak": "highlight",
            "value": false
          }
        ],
        "conditions": [
          {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.room.member"
          },
          {
            "key": "content.membership",
            "kind": "event_match",
            "pattern": "invite"
          },
          {
            "key": "state_key",
            "kind": "event_match",
            "pattern": "@alice:example.com"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.invite_for_me"
      },
      {
        "actions": [
          "notify",
          {
            "set_tweak": "highlight",
            "value": false
          }
        ],
        "conditions": [
          {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.room.member"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.member_event"
      },
      {
        "actions": [
          "notify",
          {
            "set_tweak": "highlight",
            "value": false
          }
        ],
        "conditions": [
          {
            "key": "type",
            "kind": "event_match",
            "pattern": "m.room.message"
          }
        ],
        "default": true,
        "enabled": true,
        "rule_id": ".m.rule.message"
      }
    ]
  }
}

GET /_matrix/client/v3/pushrules/global/


Retrieve all push rules for this user.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 All the push rules for this user.

200 response

Name Type Description
content [PushRule]
override [PushRule]
room [PushRule]
sender [PushRule]
underride [PushRule]
PushRule
Name Type Description
actions [string|object]

Required: The actions to perform when this rule is matched.

conditions [PushCondition]

The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Only applicable to underride and override rules.

default boolean

Required: Whether this is a default rule, or has been set explicitly.

enabled boolean

Required: Whether the push rule is enabled or not.

pattern string

The glob-style pattern to match against. Only applicable to content rules.

rule_id string

Required: The ID of this rule.

PushCondition
Name Type Description
is string

Required for room_member_count conditions. A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.

key string

Required for event_match, event_property_is and event_property_contains conditions. The dot-separated field of the event to match.

Required for sender_notification_permission conditions. The field in the power level event the user needs a minimum power level for. Fields must be specified under the notifications property in the power level event’s content.

kind string

Required: The kind of condition to apply. See conditions for more information on the allowed kinds and how they work.

pattern string

Required for event_match conditions. The glob-style pattern to match against.

value string|integer|boolean|null

Required for event_property_is and event_property_contains conditions. A non-compound canonical JSON value to match against.

{
  "content": [
    {
      "actions": [
        "notify",
        {
          "set_tweak": "sound",
          "value": "default"
        },
        {
          "set_tweak": "highlight"
        }
      ],
      "default": true,
      "enabled": true,
      "pattern": "alice",
      "rule_id": ".m.rule.contains_user_name"
    }
  ],
  "override": [
    {
      "actions": [],
      "conditions": [],
      "default": true,
      "enabled": false,
      "rule_id": ".m.rule.master"
    },
    {
      "actions": [],
      "conditions": [
        {
          "key": "content.msgtype",
          "kind": "event_match",
          "pattern": "m.notice"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.suppress_notices"
    }
  ],
  "room": [],
  "sender": [],
  "underride": [
    {
      "actions": [
        "notify",
        {
          "set_tweak": "sound",
          "value": "ring"
        },
        {
          "set_tweak": "highlight",
          "value": false
        }
      ],
      "conditions": [
        {
          "key": "type",
          "kind": "event_match",
          "pattern": "m.call.invite"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.call"
    },
    {
      "actions": [
        "notify",
        {
          "set_tweak": "sound",
          "value": "default"
        },
        {
          "set_tweak": "highlight"
        }
      ],
      "conditions": [
        {
          "kind": "contains_display_name"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.contains_display_name"
    },
    {
      "actions": [
        "notify",
        {
          "set_tweak": "sound",
          "value": "default"
        },
        {
          "set_tweak": "highlight",
          "value": false
        }
      ],
      "conditions": [
        {
          "is": "2",
          "kind": "room_member_count"
        },
        {
          "key": "type",
          "kind": "event_match",
          "pattern": "m.room.message"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.room_one_to_one"
    },
    {
      "actions": [
        "notify",
        {
          "set_tweak": "sound",
          "value": "default"
        },
        {
          "set_tweak": "highlight",
          "value": false
        }
      ],
      "conditions": [
        {
          "key": "type",
          "kind": "event_match",
          "pattern": "m.room.member"
        },
        {
          "key": "content.membership",
          "kind": "event_match",
          "pattern": "invite"
        },
        {
          "key": "state_key",
          "kind": "event_match",
          "pattern": "@alice:example.com"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.invite_for_me"
    },
    {
      "actions": [
        "notify",
        {
          "set_tweak": "highlight",
          "value": false
        }
      ],
      "conditions": [
        {
          "key": "type",
          "kind": "event_match",
          "pattern": "m.room.member"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.member_event"
    },
    {
      "actions": [
        "notify",
        {
          "set_tweak": "highlight",
          "value": false
        }
      ],
      "conditions": [
        {
          "key": "type",
          "kind": "event_match",
          "pattern": "m.room.message"
        }
      ],
      "default": true,
      "enabled": true,
      "rule_id": ".m.rule.message"
    }
  ]
}

GET /_matrix/client/v3/pushrules/global/{kind}/{ruleId}


Retrieve a single specified push rule.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule.


Responses

Status Description
200 The specific push rule. This will also include keys specific to the rule itself such as the rule’s actions and conditions if set.
404 The push rule does not exist.

200 response

PushRule
Name Type Description
actions [string|object]

Required: The actions to perform when this rule is matched.

conditions [PushCondition]

The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Only applicable to underride and override rules.

default boolean

Required: Whether this is a default rule, or has been set explicitly.

enabled boolean

Required: Whether the push rule is enabled or not.

pattern string

The glob-style pattern to match against. Only applicable to content rules.

rule_id string

Required: The ID of this rule.

PushCondition
Name Type Description
is string

Required for room_member_count conditions. A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.

key string

Required for event_match, event_property_is and event_property_contains conditions. The dot-separated field of the event to match.

Required for sender_notification_permission conditions. The field in the power level event the user needs a minimum power level for. Fields must be specified under the notifications property in the power level event’s content.

kind string

Required: The kind of condition to apply. See conditions for more information on the allowed kinds and how they work.

pattern string

Required for event_match conditions. The glob-style pattern to match against.

value string|integer|boolean|null

Required for event_property_is and event_property_contains conditions. A non-compound canonical JSON value to match against.

{
  "actions": [],
  "default": false,
  "enabled": true,
  "pattern": "cake*lie",
  "rule_id": "nocake"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

PUT /_matrix/client/v3/pushrules/global/{kind}/{ruleId}


This endpoint allows the creation and modification of user defined push rules.

If a rule with the same rule_id already exists among rules of the same kind, it is updated with the new parameters, otherwise a new rule is created.

If both after and before are provided, the new or updated rule must be the next most important rule with respect to the rule identified by before.

If neither after nor before are provided and the rule is created, it should be added as the most important user defined rule among rules of the same kind.

When creating push rules, they MUST be enabled by default.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule. If the string starts with a dot ("."), the request MUST be rejected as this is reserved for server-default rules. Slashes ("/") and backslashes ("\") are also not allowed.

query parameters
Name Type Description
after string

This makes the new rule the next-less important rule relative to the given user defined rule. It is not possible to add a rule relative to a predefined server rule.

before string

Use ‘before’ with a rule_id as its value to make the new rule the next-most important rule with respect to the given user defined rule. It is not possible to add a rule relative to a predefined server rule.

Request body

Name Type Description
actions [string|object]

Required: The action(s) to perform when the conditions for this rule are met.

conditions [PushCondition]

The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Only applicable to underride and override rules.

pattern string

Only applicable to content rules. The glob-style pattern to match against.

PushCondition
Name Type Description
is string

Required for room_member_count conditions. A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.

key string

Required for event_match, event_property_is and event_property_contains conditions. The dot-separated field of the event to match.

Required for sender_notification_permission conditions. The field in the power level event the user needs a minimum power level for. Fields must be specified under the notifications property in the power level event’s content.

kind string

Required: The kind of condition to apply. See conditions for more information on the allowed kinds and how they work.

pattern string

Required for event_match conditions. The glob-style pattern to match against.

value string|integer|boolean|null

Required for event_property_is and event_property_contains conditions. A non-compound canonical JSON value to match against.

Request body example

{
  "actions": [
    "notify"
  ],
  "pattern": "cake*lie"
}

Responses

Status Description
200 The push rule was created/updated.
400 There was a problem configuring this push rule.
404 The push rule does not exist (when updating a push rule).
429 This request was rate-limited.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNKNOWN",
  "error": "before/after rule not found: someRuleId"
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

DELETE /_matrix/client/v3/pushrules/global/{kind}/{ruleId}


This endpoint removes the push rule defined in the path.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule.


Responses

Status Description
200 The push rule was deleted.
404 The push rule does not exist.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

GET /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/actions


This endpoint get the actions for the specified push rule.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule.


Responses

Status Description
200 The actions for this push rule.
404 The push rule does not exist.

200 response

Name Type Description
actions [string|object]

Required: The action(s) to perform for this rule.

{
  "actions": [
    "notify",
    {
      "set_tweak": "sound",
      "value": "bing"
    }
  ]
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

PUT /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/actions


This endpoint allows clients to change the actions of a push rule. This can be used to change the actions of builtin rules.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule.

Request body

Name Type Description
actions [string|object]

Required: The action(s) to perform for this rule.

Request body example

{
  "actions": [
    "notify",
    {
      "set_tweak": "highlight"
    }
  ]
}

Responses

Status Description
200 The actions for the push rule were set.
404 The push rule does not exist.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

GET /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/enabled


This endpoint gets whether the specified push rule is enabled.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule.


Responses

Status Description
200 Whether the push rule is enabled.
404 The push rule does not exist.

200 response

Name Type Description
enabled boolean

Required: Whether the push rule is enabled or not.

{
  "enabled": true
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

PUT /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/enabled


This endpoint allows clients to enable or disable the specified push rule.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
kind string

Required: The kind of rule

One of: [override, underride, sender, room, content].

ruleId string

Required: The identifier for the rule.

Request body

Name Type Description
enabled boolean

Required: Whether the push rule is enabled or not.

Request body example

{
  "enabled": true
}

Responses

Status Description
200 The push rule was enabled or disabled.
404 The push rule does not exist.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The push rule was not found."
}

推送规则:事件

当用户更改推送规则,会向所有客户端在下次 /sync 请求的 account_data 部分发送 m.push_rules 事件。 事件内容为用户当前的全部推送规则。

m.push_rules


Describes all push rules for this user.

Event type: Message event

Content

Name Type Description
global Ruleset

The global ruleset

Ruleset
Name Type Description
content [PushRule]
override [PushRule]
room [PushRule]
sender [PushRule]
underride [PushRule]
PushRule
Name Type Description
actions [string|object]

Required: The actions to perform when this rule is matched.

conditions [PushCondition]

The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Only applicable to underride and override rules.

default boolean

Required: Whether this is a default rule, or has been set explicitly.

enabled boolean

Required: Whether the push rule is enabled or not.

pattern string

The glob-style pattern to match against. Only applicable to content rules.

rule_id string

Required: The ID of this rule.

PushCondition
Name Type Description
is string

Required for room_member_count conditions. A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.

key string

Required for event_match, event_property_is and event_property_contains conditions. The dot-separated field of the event to match.

Required for sender_notification_permission conditions. The field in the power level event the user needs a minimum power level for. Fields must be specified under the notifications property in the power level event’s content.

kind string

Required: The kind of condition to apply. See conditions for more information on the allowed kinds and how they work.

pattern string

Required for event_match conditions. The glob-style pattern to match against.

value string|integer|boolean|null

Required for event_property_is and event_property_contains conditions. A non-compound canonical JSON value to match against.

Examples

{
  "content": {
    "global": {
      "content": [
        {
          "actions": [
            "notify",
            {
              "set_tweak": "sound",
              "value": "default"
            },
            {
              "set_tweak": "highlight"
            }
          ],
          "default": true,
          "enabled": true,
          "pattern": "alice",
          "rule_id": ".m.rule.contains_user_name"
        }
      ],
      "override": [
        {
          "actions": [],
          "conditions": [],
          "default": true,
          "enabled": false,
          "rule_id": ".m.rule.master"
        },
        {
          "actions": [],
          "conditions": [
            {
              "key": "content.msgtype",
              "kind": "event_match",
              "pattern": "m.notice"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.suppress_notices"
        }
      ],
      "room": [],
      "sender": [],
      "underride": [
        {
          "actions": [
            "notify",
            {
              "set_tweak": "sound",
              "value": "ring"
            },
            {
              "set_tweak": "highlight",
              "value": false
            }
          ],
          "conditions": [
            {
              "key": "type",
              "kind": "event_match",
              "pattern": "m.call.invite"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.call"
        },
        {
          "actions": [
            "notify",
            {
              "set_tweak": "sound",
              "value": "default"
            },
            {
              "set_tweak": "highlight"
            }
          ],
          "conditions": [
            {
              "kind": "contains_display_name"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.contains_display_name"
        },
        {
          "actions": [
            "notify",
            {
              "set_tweak": "sound",
              "value": "default"
            },
            {
              "set_tweak": "highlight",
              "value": false
            }
          ],
          "conditions": [
            {
              "is": "2",
              "kind": "room_member_count"
            },
            {
              "key": "type",
              "kind": "event_match",
              "pattern": "m.room.message"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.room_one_to_one"
        },
        {
          "actions": [
            "notify",
            {
              "set_tweak": "sound",
              "value": "default"
            },
            {
              "set_tweak": "highlight",
              "value": false
            }
          ],
          "conditions": [
            {
              "key": "type",
              "kind": "event_match",
              "pattern": "m.room.member"
            },
            {
              "key": "content.membership",
              "kind": "event_match",
              "pattern": "invite"
            },
            {
              "key": "state_key",
              "kind": "event_match",
              "pattern": "@alice:example.com"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.invite_for_me"
        },
        {
          "actions": [
            "notify",
            {
              "set_tweak": "highlight",
              "value": false
            }
          ],
          "conditions": [
            {
              "key": "type",
              "kind": "event_match",
              "pattern": "m.room.member"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.member_event"
        },
        {
          "actions": [
            "notify",
            {
              "set_tweak": "highlight",
              "value": false
            }
          ],
          "conditions": [
            {
              "key": "type",
              "kind": "event_match",
              "pattern": "m.room.message"
            }
          ],
          "default": true,
          "enabled": true,
          "rule_id": ".m.rule.message"
        }
      ]
    }
  },
  "type": "m.push_rules"
}
示例

为 ID 为 !dj234r78wl45Gh4D:matrix.org 的房间创建禁止通知的规则:

curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \
'{
   "actions" : []
 }'

禁止为用户名为 @spambot:matrix.org 的用户发送通知:

curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \
'{
   "actions" : []
 }'

为所有消息内容含 “cake” 的消息始终通知,并设置专用提示音(规则 ID 为 SSByZWFsbHkgbGlrZSBjYWtl):

curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \
'{
   "pattern": "cake",
   "actions" : ["notify", {"set_tweak":"sound", "value":"cakealarm.wav"}]
 }'

添加规则:禁止通知以 “cake” 开头、“lie” 结尾的消息,并优先级高于上一条规则:

curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \
'{
   "pattern": "cake*lie",
   "actions" : ["notify"]
 }'

为成员数不超过 10 的房间内含有 “beer” 的消息添加自定义通知音(优先级高于 room, sender, content 规则):

curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \
'{
   "conditions": [
     {"kind": "event_match", "key": "content.body", "pattern": "beer" },
     {"kind": "room_member_count", "is": "<=10"}
   ],
   "actions" : [
     "notify",
     {"set_tweak":"sound", "value":"beeroclock.wav"}
   ]
 }'

客户端行为

客户端必须先配置 Pusher,才能接收推送通知。具体 API 如下所述。

GET /_matrix/client/v3/pushers


Gets all currently active pushers for the authenticated user.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The pushers for this user.

200 response

Name Type Description
pushers [Pusher]

An array containing the current pushers for the user

Pusher
Name Type Description
app_display_name string

Required: A string that will allow the user to identify what application owns this pusher.

app_id string

Required: This is a reverse-DNS style identifier for the application. Max length, 64 chars.

data PusherData

Required: A dictionary of information for the pusher implementation itself.

device_display_name string

Required: A string that will allow the user to identify what device owns this pusher.

kind string

Required: The kind of pusher. "http" is a pusher that sends HTTP pokes.

lang string

Required: The preferred language for receiving notifications (e.g. ’en' or ’en-US')

profile_tag string

This string determines which set of device specific rules this pusher executes.

pushkey string

Required: This is a unique identifier for this pusher. See /set for more detail. Max length, 512 bytes.

PusherData
Name Type Description
format string

The format to use when sending notifications to the Push Gateway.

url URI

Required if kind is http. The URL to use to send notifications to.

{
  "pushers": [
    {
      "app_display_name": "Appy McAppface",
      "app_id": "face.mcapp.appy.prod",
      "data": {
        "url": "https://example.com/_matrix/push/v1/notify"
      },
      "device_display_name": "Alice's Phone",
      "kind": "http",
      "lang": "en-US",
      "profile_tag": "xyz",
      "pushkey": "Xp/MzCt8/9DcSNE9cuiaoT5Ac55job3TdLSSmtmYl4A="
    }
  ]
}

POST /_matrix/client/v3/pushers/set


This endpoint allows the creation, modification and deletion of pushers for this user ID. The behaviour of this endpoint varies depending on the values in the JSON body.

If kind is not null, the pusher with this app_id and pushkey for this user is updated, or it is created if it doesn’t exist. If kind is null, the pusher with this app_id and pushkey for this user is deleted.

Rate-limited: Yes
Requires authentication: Yes

Request

Request body

Name Type Description
app_display_name string

Required if kind is not null. A string that will allow the user to identify what application owns this pusher.

app_id string

Required: This is a reverse-DNS style identifier for the application. It is recommended that this end with the platform, such that different platform versions get different app identifiers. Max length, 64 chars.

If the kind is "email", this is "m.email".

append boolean

If true, the homeserver should add another pusher with the given pushkey and App ID in addition to any others with different user IDs. Otherwise, the homeserver must remove any other pushers with the same App ID and pushkey for different users. The default is false.

data PusherData

Required if kind is not null. A dictionary of information for the pusher implementation itself.

If kind is http, this MUST contain url which is the URL to use for sending notifications. Clients MAY use this object to pass custom data to their push gateway. Servers MUST forward the entire content including format and any custom keys but excluding url when calling /_matrix/push/v1/notify.

device_display_name string

Required if kind is not null. A string that will allow the user to identify what device owns this pusher.

kind string|null

Required: The kind of pusher to configure. "http" makes a pusher that sends HTTP pokes. "email" makes a pusher that emails the user with unread notifications. null deletes the pusher.

lang string

Required if kind is not null. The preferred language for receiving notifications (e.g. ’en’ or ’en-US’).

profile_tag string

This string determines which set of device specific rules this pusher executes.

pushkey string

Required: This is a unique identifier for this pusher. The value you should use for this is the routing or destination address information for the notification, for example, the APNS token for APNS or the Registration ID for GCM. If your notification client has no such concept, use any unique identifier. Max length, 512 bytes.

If the kind is "email", this is the email address to send notifications to.

PusherData
Name Type Description
format string

The format to send notifications in to Push Gateways if the kind is http. The details about what fields the homeserver should send to the push gateway are defined in the Push Gateway Specification. Currently the only format available is ’event_id_only'.

url URI

Required if kind is http. The URL to use for sending notifications. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify.

Request body example

{
  "app_display_name": "Mat Rix",
  "app_id": "com.example.app.ios",
  "append": false,
  "data": {
    "format": "event_id_only",
    "url": "https://push-gateway.location.here/_matrix/push/v1/notify"
  },
  "device_display_name": "iPhone 9",
  "kind": "http",
  "lang": "en",
  "profile_tag": "xxyyzz",
  "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ"
}

Responses

Status Description
200 The pusher was set.
400 One or more of the pusher values were invalid.
429 This request was rate-limited.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_MISSING_PARAM",
  "error": "Missing parameters: lang, data"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
列出通知

客户端可获取已收到通知的事件列表,帮助用户查看收到的重要消息摘要。

GET /_matrix/client/v3/notifications


This API is used to paginate through the list of events that the user has been, or would have been notified about.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
from string

Pagination token to continue from. This should be the next_token returned from an earlier call to this endpoint.

limit integer

Limit on the number of events to return in this request.

only string

Allows basic filtering of events returned. Supply highlight to return only events where the notification had the highlight tweak set.


Responses

Status Description
200 A batch of events is being returned

200 response

Name Type Description
next_token string

The token to supply in the from param of the next /notifications request in order to request more events. If this is absent, there are no more results.

notifications [Notification]

Required: The list of events that triggered notifications.

Notification
Name Type Description
actions [object|string]

Required: The action(s) to perform when the conditions for this rule are met. See Push Rules: API.

event Event

Required: The Event object for the event that triggered the notification.

profile_tag string

The profile tag of the rule that matched this event.

read boolean

Required: Indicates whether the user has sent a read receipt indicating that they have read this message.

room_id string

Required: The ID of the room in which the event was posted.

ts integer

Required: The unix timestamp at which the event notification was sent, in milliseconds.

Event
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEventWithoutRoomID

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "next_token": "abcdef",
  "notifications": [
    {
      "actions": [
        "notify"
      ],
      "event": {
        "content": {
          "body": "This is an example text message",
          "format": "org.matrix.custom.html",
          "formatted_body": "<b>This is an example text message</b>",
          "msgtype": "m.text"
        },
        "event_id": "$143273582443PhrSn:example.org",
        "origin_server_ts": 1432735824653,
        "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
        "sender": "@example:example.org",
        "type": "m.room.message",
        "unsigned": {
          "age": 1234,
          "membership": "join"
        }
      },
      "profile_tag": "hcbvkzxhcvb",
      "read": true,
      "room_id": "!abcdefg:example.com",
      "ts": 1475508881945
    }
  ]
}
接收通知

服务器必须在客户端的 /sync 流中包含未读通知数,并随计数变化更新。通知判定依赖于事件适用的推送规则。

对于加密事件,主服务器仅有限访问事件内容,推送规则需由客户端在解密后处理,客户端收到每条事件都需执行推送规则。这可能导致需修正从主服务器收到的未读通知数。

标记通知为已读

当用户更新已读回执(无论使用 API 还是通过发送事件),在该事件之前(含自身)的通知必须被标记为已读。具体被影响的事件取决于是否使用了线程已读回执。用户可同时发送 m.readm.read.private 回执,两者都可清除通知。

如同一房间内用户同时拥有 m.readm.read.private,应取更“新”或“更靠前”的回执为判断依据。例如,若事件 A、B、C、D 按时间升序排列,m.read 回执在事件 C,m.read.private 在事件 A,则用户已读至 C。如果 m.read.private 更新为 B 或 C,通知状态不变(m.read 回执仍领先);如 m.read.private 更新为 D,则用户已读到 D(m.read 落后于 m.read.private)。

[Added in v1.4] 处理线程已读回执时,服务器需将通知数分配至各线程(主时间线看作一条线程)。判定事件属于哪个线程,服务器应按event 关系查找,直到遇到 m.thread 关系定义的根事件(详见线程模块),但不建议无限遍历。建议实现时至多跳 3 层,未找到线程即视为事件不属于线程。主要确保后续事件如 m.reaction 被正确划分为某线程。

服务器行为

主服务器收到新事件时,为房间内每位本地用户(不含发信人)处理推送规则,结果可能为:

  • 生成新的未读通知数;
  • 向配置的推送网关发起请求。

新事件导致的未读通知数必须与事件本身一起在同一次 /sync 响应中返回。

推送网关行为

APNS 推荐

APNS 推送通知的具体格式灵活,由客户端应用与其推送网关约定。由于 APNS 需求发送者具有应用开发者的私钥,每个应用需有专属推送网关。推荐如下:

  • APNS Token 基于 base64 编码,直接用于 pushkey。
  • 正式环境和沙箱环境使用不同的 app_id 。
  • APNS 推送网关不必等待 APNS 网关返回错误再响应;可记录失败,并在下次推送相同 pushkey 时返回 ‘rejected’。

安全性注意事项

客户端需指定用于发送事件通知的推送网关 URL 。此 URL 必须为 HTTPS,绝不能是 HTTP。

推送通知会经过推送供应商,消息内容应尽量不随推送本体一起发送。推送网关应发送 “sync” 指令,指导客户端直接向主服务器获取新事件。

第三方邀请

本模块为邀请新成员加入房间提供了支持,即使对方的 Matrix 用户 ID 未知,也可以通过第三方标识符(如电子邮件地址)进行邀请。此处包含两种流程:一种是已知该第三方标识符对应的 Matrix 用户 ID,另一种是未知。无论哪种情况,客户端都通过 /invite 接口并提供第三方标识符的详细信息来发起邀请。

主服务器会向身份服务器查询该标识符是否对应已知的 Matrix 用户 ID:

  • 如果已知,则直接向该用户发出邀请。
  • 如果未知,主服务器会请求身份服务器记录该邀请的详细信息,并在未来为该标识符分配绑定时通知被邀请者的主服务器有待处理的邀请。身份服务器会向发起邀请的主服务器返回一个令牌和公钥。

当被邀请者的主服务器收到绑定通知时,应在房间的事件图中插入一个 m.room.member 事件,其中 content.membershipinvite,同时包含一个 content.third_party_invite 属性,以证明被邀请者确实拥有该第三方标识符。更多信息请参见 m.room.member 事件架构说明。

事件

m.room.third_party_invite


Acts as an m.room.member invite event, where there isn’t a target user_id to invite. This event contains a token and a public key whose private key must be used to sign the token. Any user who can present that signature may use this invitation to join the target room.

Event type: State event
State key The token, of which a signature must be produced in order to join the room.

Content

Name Type Description
display_name string

Required: A user-readable string which represents the user who has been invited. This should not contain the user’s third-party ID, as otherwise when the invite is accepted it would leak the association between the matrix ID and the third-party ID.

key_validity_url string

Required: A URL which can be fetched, with querystring public_key=public_key, to validate whether the key has been revoked. The URL must return a JSON object containing a boolean property named ‘valid’.

public_key string

Required: A base64-encoded ed25519 key with which token must be signed (though a signature from any entry in public_keys is also sufficient). This exists for backwards compatibility.

public_keys [PublicKeys]

Keys with which the token may be signed.

PublicKeys
Name Type Description
key_validity_url string

An optional URL which can be fetched, with querystring public_key=public_key, to validate whether the key has been revoked. The URL must return a JSON object containing a boolean property named ‘valid’. If this URL is absent, the key must be considered valid indefinitely.

public_key string

Required: A base-64 encoded ed25519 key with which token may be signed.

Examples

{
  "content": {
    "display_name": "Alice Margatroid",
    "key_validity_url": "https://magic.forest/verifykey",
    "public_key": "abc123",
    "public_keys": [
      {
        "key_validity_url": "https://magic.forest/verifykey",
        "public_key": "def456"
      }
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "pc98",
  "type": "m.room.third_party_invite",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

客户端通过第三方标识符请求服务器邀请用户。

POST /_matrix/client/v3/rooms/{roomId}/invite


Note that there are two forms of this API, which are documented separately. This version of the API does not require that the inviter know the Matrix identifier of the invitee, and instead relies on third-party identifiers. The homeserver uses an identity server to perform the mapping from third-party identifier to a Matrix identifier. The other is documented in the joining rooms section.

This API invites a user to participate in a particular room. They do not start participating in the room until they actually join the room.

Only users currently in a particular room can invite other users to join that room.

If the identity server did know the Matrix user identifier for the third-party identifier, the homeserver will append a m.room.member event to the room.

If the identity server does not know a Matrix user identifier for the passed third-party identifier, the homeserver will issue an invitation which can be accepted upon providing proof of ownership of the third- party identifier. This is achieved by the identity server generating a token, which it gives to the inviting homeserver. The homeserver will add an m.room.third_party_invite event into the graph for the room, containing that token.

When the invitee binds the invited third-party identifier to a Matrix user ID, the identity server will give the user a list of pending invitations, each containing:

  • The room ID to which they were invited

  • The token given to the homeserver

  • A signature of the token, signed with the identity server’s private key

  • The matrix user ID who invited them to the room

If a token is requested from the identity server, the homeserver will append a m.room.third_party_invite event to the room.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room identifier (not alias) to which to invite the user.

Request body

Invite3pid
Name Type Description
address string

Required: The invitee’s third-party identifier.

id_access_token string

Required: An access token previously registered with the identity server. Servers can treat this as optional to distinguish between r0.5-compatible clients and this specification version.

id_server string

Required: The hostname+port of the identity server which should be used for third-party identifier lookups.

medium string

Required: The kind of address being passed in the address field, for example email (see the list of recognised values).

Request body example

{
  "address": "cheeky@monkey.com",
  "id_access_token": "abc123_OpaqueString",
  "id_server": "matrix.org",
  "medium": "email"
}

Responses

Status Description
200 The user has been invited to join the room.
403

You do not have permission to invite the user to the room. A meaningful errcode and description error text will be returned. Example reasons for rejections are:

  • The invitee has been banned from the room.
  • The invitee is already a member of the room.
  • The inviter is not currently in the room.
  • The inviter’s power level is insufficient to invite users to the room.
429 This request was rate-limited.

200 response

{}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "@cheeky_monkey:matrix.org is banned from the room"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

服务器行为

在收到 /invite 请求后,服务器需要使用指定的身份服务器查询第三方标识符。如果查询结果返回了 Matrix 用户 ID,则可以启动标准的邀请流程。该流程如下所示:

    +---------+                         +-------------+                                    +-----------------+
    | 客户端  |                         | 主服务器    |                                    | 身份服务器      |
    +---------+                         +-------------+                                    +-----------------+
        |                                    |                                                    |
        | POST /invite                       |                                                    |
        |----------------------------------->|                                                    |
        |                                    |                                                    |
        |                                    | GET /lookup                                        |
        |                                    |--------------------------------------------------->|
        |                                    |                                                    |
        |                                    |                                     用户 ID 结果   |
        |                                    |<---------------------------------------------------|
        |                                    |                                                    |
        |                                    | 对发现的用户 ID 启动邀请流程                       |
        |                                    |------------------------------------------           |
        |                                    |                                         |           |
        |                                    |<-----------------------------------------           |
        |                                    |                                                    |
        |        完成 /invite 请求            |                                                    |
        |<-----------------------------------|                                                    |
        |                                    |                                                    |

然而,如果查询结果没有返回已绑定的用户 ID,主服务器必须将邀请信息存储在身份服务器上,并向房间发出有效的 m.room.third_party_invite 事件。该流程如下所示:

    +---------+                         +-------------+                                               +-----------------+
    | 客户端  |                         | 主服务器    |                                               | 身份服务器      |
    +---------+                         +-------------+                                               +-----------------+
        |                                    |                                                             |
        | POST /invite                       |                                                             |
        |----------------------------------->|                                                             |
        |                                    |                                                             |
        |                                    | GET /lookup                                                 |
        |                                    |------------------------------------------------------------>|
        |                                    |                                                             |
        |                                    |                                        “无用户” 结果         |
        |                                    |<------------------------------------------------------------|
        |                                    |                                                             |
        |                                    | POST /store-invite                                          |
        |                                    |------------------------------------------------------------>|
        |                                    |                                                             |
        |                                    |         m.room.third_party_invite 事件所需信息               |
        |                                    |<------------------------------------------------------------|
        |                                    |                                                             |
        |                                    | 向房间发出 m.room.third_party_invite 事件                    |
        |                                    |-------------------------------------------                   |
        |                                    |                                          |                   |
        |                                    |<------------------------------------------                   |
        |                                    |                                                             |
        |        完成 /invite 请求            |                                                             |
        |<-----------------------------------|                                                             |
        |                                    |                                                             |

所有主服务器必须验证事件中 content.third_party_invite.signed 对象的签名。

第三方用户随后需要验证其身份,这将使身份服务器调用主服务器,将该第三方标识符绑定到用户的主服务器。此时,主服务器会将房间中的 m.room.third_party_invite 事件替换为该用户的完整 membership: invitem.room.member 事件。

如果主服务器是通过 m.room.third_party_invite 首次加入某个房间,则已在该房间中的服务器(根据标准服务器间协议选定)必须校验用于签名的公钥仍然有效,方法即如上文所述检查 key_validity_url

其他主服务器不得仅因 key_validity_url 拒绝房间加入请求,这是为了确保所有主服务器都能获得一致的房间视图。但主服务器可以向其客户端指出成员的成员资格可能存在疑问。

例如,假设 H1、H2、H3 为主服务器,UserA 是 H1 的用户,身份服务器为 IS,第三方邀请的完整流程如下图所示。图中假定 H1、H2 已在房间,H3 尝试加入。

    +-------+ +-----------------+         +-----+                                          +-----+           +-----+                      +-----+
    | UserA | | 第三方用户      |         | H1  |                                          | H2  |           | H3  |                      | IS  |
    +-------+ +-----------------+         +-----+                                          +-----+           +-----+                      +-----+
        |             |                    |                                                |                 |                            |
        | POST /invite 针对第三方用户       |                                                |                 |                            |
        |--------------------------------->|                                                |                 |                            |
        |             |                    |                                                |                 |                            |
        |             |                    | GET /lookup                                    |                 |                            |
        |             |                    |---------------------------------------------------------------------------------------------->|
        |             |                    |                                                |                 |                            |
        |             |                    |                                                |                查询结果(空对象)           |
        |             |                    |<----------------------------------------------------------------------------------------------|
        |             |                    |                                                |                 |                            |
        |             |                    | POST /store-invite                             |                 |                            |
        |             |                    |---------------------------------------------------------------------------------------------->|
        |             |                    |                                                |                 |                            |
        |             |                    |                                                |   第三方邀请生成的令牌、公钥等                |
        |             |                    |<----------------------------------------------------------------------------------------------|
        |             |                    |                                                |                 |                            |
        |             |                    | (联邦)向房间发出 m.room.third_party_invite    |                 |                            |
        |             |                    |----------------------------------------------->|                 |                            |
        |             |                    |                                                |                 |                            |
        |          完成 /invite 请求        |                                                |                 |                            |
        |<---------------------------------|                                                |                 |                            |
        |             |                    |                                                |                 |                            |
        |             |   验证身份         |                                                |                 |                            |
        |             |-------------------------------------------------------------------------------------------------------------------->|
        |             |                    |                                                |                 |                            |
        |             |                    |                                                |                 |         POST /3pid/onbind  |
        |             |                    |                                                |                 |<---------------------------|
        |             |                    |                                                |                 |                            |
        |             |                    |                 PUT /exchange_third_party_invite/:roomId         |                            |
        |             |                    |<-----------------------------------------------------------------|                            |
        |             |                    |                                                |                 |                            |
        |             |                    | 验证该请求                                       |                 |                            |
        |             |                    |-------------------                               |                 |                            |
        |             |                    |                  |                               |                 |                            |
        |             |                    |<------------------                               |                 |                            |
        |             |                    |                                                |                 |                            |
        |             |                    | (联邦)发出 m.room.member 邀请                  |                 |                            |
        |             |                    |----------------------------------------------->|                 |                            |
        |             |                    |                                                |                 |                            |
        |             |                    |                                                |                 |                            |
        |             |                    | (联邦)将 m.room.member 事件发送给 H2           |                            |
        |             |                    |----------------------------------------------------------------->|                            |
        |             |                    |                                                |                 |                            |
        |             |                    | 完成 /exchange_third_party_invite/:roomId 请求    |                            |
        |             |                    |----------------------------------------------------------------->|                            |
        |             |                    |                                                |                 |                            |
        |             |                    |                                                |                 | 加入房间                    |
        |             |                    |                                                |                 |------------------------    |
        |             |                    |                                                |                 |                       |    |
        |             |                    |                                                |                 |<-----------------------    |
        |             |                    |                                                |                 |                            |

注意当 H1 向 H2 和 H3 发送 m.room.member 事件时,H1 不需要等待任何服务器确认收到该事件。同样,H1 可以在向 H2、H3 发送 m.room.member 事件的同时完成 /exchange_third_party_invite 请求。另外,H3 可以在任意时刻完成其从 IS 接收到的 /3pid/onbind 请求——此流程中的完成未在图中展示。

H1 必须校验来自 H3 的请求,确保 signed 属性正确,且 key_validity_url 仍有效。此操作需向 身份服务器 /isvalid 端点发起请求,且应使用已提供的 URL 而非自行构造。查询字符串和返回值必须符合身份服务规范。

不允许其他主服务器仅基于校验 key_validity_url 的结果拒绝事件,因为我们必须保证事件的接受方式具备确定性。如果某些参与服务器无法连接到密钥服务器、密钥服务器宕机或吊销密钥,则其他服务器会拒绝该事件,导致参与服务器的事件图发生分歧。此行为依赖参与服务器间的信任,但该信任已通过服务器间协议隐含。此外,还必须完成公钥签名验证,从而最大限度减少攻击面。

安全性考虑

本模块涉及若干隐私和信任问题。

为保护用户隐私,必须强力防止 Matrix 用户 ID 与第三方标识符之间的映射泄露。尤其是,应尽量阻止通过 Matrix 用户 ID 查找所有第三方标识符(从而能够关联各第三方标识符)。为此,任何事件都不会直接包含第三方标识符,而是采用由身份服务器提供的不透明显示名称。客户端不应因邀请而记住或显示第三方标识符,仅限于邀请方自身的使用。

主服务器不需要信任特定的身份服务器。一般而言,由客户端自行决定信任哪些身份服务器,而非主服务器决定。因此,此 API 从最终用户处获取身份服务器,并未指定受信任服务器集。当然,一些主服务器可能会为其用户提供默认配置或拒绝个别身份服务器,但主服务器无权对其他主服务器的用户信任哪些身份服务器进行干预。

身份服务器或主服务器可能因收到大量请求或存储大量状态而面临拒绝服务攻击风险。如何防御此类风险由实现方自行决定。

服务器端搜索

搜索 API 允许客户端对用户所加入过的所有房间中的事件进行全文搜索,包括用户已经离开的房间。仅搜索用户有权限查看的事件,例如,用户离开房间后发生的事件将不会被包含。

客户端行为

服务器端搜索有一个统一的 HTTP API,具体文档如下。

POST /_matrix/client/v3/search


Performs a full text search across different categories.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
next_batch string

The point to return events from. If given, this should be a next_batch result from a previous call to this endpoint.

Request body

Name Type Description
search_categories Categories

Required: Describes which categories to search in and their criteria.

Categories
Name Type Description
room_events Room Events Criteria

Mapping of category name to search criteria.

Room Events Criteria
Name Type Description
event_context Include Event Context

Configures whether any context for the events returned are included in the response.

filter Filter

This takes a filter.

groupings Groupings

Requests that the server partitions the result set based on the provided list of keys.

include_state boolean

Requests the server return the current state for each room returned.

keys [string]

The keys to search. Defaults to all.

order_by string

The order in which to search for results. By default, this is "rank".

One of: [recent, rank].

search_term string

Required: The string to search events for

Include Event Context
Name Type Description
after_limit integer

How many events after the result are returned. By default, this is 5.

before_limit integer

How many events before the result are returned. By default, this is 5.

include_profile boolean

Requests that the server returns the historic profile information for the users that sent the events that were returned. By default, this is false.

Filter
Name Type Description
contains_url boolean

If true, includes only events with a url key in their content. If false, excludes those events. If omitted, url key is not considered for filtering.

include_redundant_members boolean

If true, sends all membership events for all events, even if they have already been sent to the client. Does not apply unless lazy_load_members is true. See Lazy-loading room members for more information. Defaults to false.

lazy_load_members boolean

If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false.

limit integer

The maximum number of events to return, must be an integer greater than 0.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

not_rooms [string]

A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter.

not_senders [string]

A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter.

not_types [string]

A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A ‘*’ can be used as a wildcard to match any sequence of characters.

rooms [string]

A list of room IDs to include. If this list is absent then all rooms are included.

senders [string]

A list of senders IDs to include. If this list is absent then all senders are included.

types [string]

A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.

unread_thread_notifications boolean

If true, enables per-thread notification counts. Only applies to the /sync endpoint. Defaults to false.

Added in v1.4

Groupings
Name Type Description
group_by [Group]

List of groups to request.

Group
Name Type Description
key string

Key that defines the group.

One of: [room_id, sender].

Request body example

{
  "search_categories": {
    "room_events": {
      "groupings": {
        "group_by": [
          {
            "key": "room_id"
          }
        ]
      },
      "keys": [
        "content.body"
      ],
      "order_by": "recent",
      "search_term": "martians and men"
    }
  }
}

Responses

Status Description
200 Results of the search.
400 Part of the request was invalid.
429 This request was rate-limited.

200 response

Results
Name Type Description
search_categories Result Categories

Required: Describes which categories to search in and their criteria.

Result Categories
Name Type Description
room_events Result Room Events

Mapping of category name to search criteria.

Result Room Events
Name Type Description
count integer

An approximate count of the total number of results found.

groups {string: {string: Group Value}}

Any groups that were requested.

The outer string key is the group key requested (eg: room_id or sender). The inner string key is the grouped value (eg: a room’s ID or a user’s ID).

highlights [string]

List of words which should be highlighted, useful for stemming which may change the query terms.

next_batch string

Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. If this field is absent, there are no more results.

results [Result]

List of results in the requested order.

state {Room ID: [ClientEvent]}

The current state for every room in the results. This is included if the request had the include_state key set with a value of true.

The key is the room ID for which the State Event array belongs to.

Group Value
Name Type Description
next_batch string

Token that can be used to get the next batch of results in the group, by passing as the next_batch parameter to the next call. If this field is absent, there are no more results in this group.

order integer

Key that can be used to order different groups.

results [string]

Which results are in this group.

Result
Name Type Description
context Event Context

Context for result, if requested.

rank number

A number that describes how closely this result matches the search. Higher is closer.

result Event

The event that matched.

Event Context
Name Type Description
end string

Pagination token for the end of the chunk

events_after [Event]

Events just after the result.

events_before [Event]

Events just before the result.

profile_info {User ID: User Profile}

The historic profile information of the users that sent the events returned.

The key is the user ID for which the profile belongs to.

start string

Pagination token for the start of the chunk

Event
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

User Profile
Name Type Description
avatar_url URI
displayname string
ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

{
  "search_categories": {
    "room_events": {
      "count": 1224,
      "groups": {
        "room_id": {
          "!qPewotXpIctQySfjSy:localhost": {
            "next_batch": "BdgFsdfHSf-dsFD",
            "order": 1,
            "results": [
              "$144429830826TWwbB:localhost"
            ]
          }
        }
      },
      "highlights": [
        "martians",
        "men"
      ],
      "next_batch": "5FdgFsd234dfgsdfFD",
      "results": [
        {
          "rank": 0.00424866,
          "result": {
            "content": {
              "body": "This is an example text message",
              "format": "org.matrix.custom.html",
              "formatted_body": "<b>This is an example text message</b>",
              "msgtype": "m.text"
            },
            "event_id": "$144429830826TWwbB:localhost",
            "origin_server_ts": 1432735824653,
            "room_id": "!qPewotXpIctQySfjSy:localhost",
            "sender": "@example:example.org",
            "type": "m.room.message",
            "unsigned": {
              "age": 1234,
              "membership": "join"
            }
          }
        }
      ]
    }
  }
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

搜索类别

搜索 API 允许客户端按不同类别进行搜索。目前唯一被明确定义的类别是 room_events

room_events

该类别包含所有用户有权限查看的事件,包括用户已经离开的房间中的事件。搜索会在特定事件类型的特定键值上进行。

支持检索的字段包括:

  • m.room.message 事件的 content.body
  • m.room.name 事件的 content.name
  • m.room.topic 事件的 content.topic

加密的房间(端对端加密)不会被包含在搜索范围内。

搜索结果包含一个 rank 键,可用于按相关度排序结果。rank 值越高,结果越相关。

count 字段用于大致表示总结果数。Homeserver 可能会返回一个估计值,而非精确值。

排序方式

客户端可以指定服务器返回结果的排序方式。允许的两种排序方式为:

  • rank:首先返回最相关的结果。
  • recent:首先返回最新的结果。

默认排序方式为 rank

分组

客户端可以请求返回带有分组信息的结果,例如按 room_id 分组。在这种情况下,响应中会包含每个不同 room_id 的分组条目。每个分组条目至少包含该分组内的 event_id 列表,也可能包含关于该分组的其他元数据。

当前要求支持的分组方式有:

  • room_id
  • sender

分页

服务器响应中各处可能会返回一个 next_batch 键。它用于对结果进行分页。若需获取更多结果,客户端应使用相同的请求,并将 next_batch 查询参数设置为该标记。

分页的范围取决于 next_batch 标记返回的位置。例如,在分组内使用该标记将返回该分组中的更多结果。

目前支持的 next_batch 标记位置有:

  • search_categories.<category>.next_batch
  • search_categories.<category>.groups.<group_key>.<group_id>.next_batch

即使存在更多匹配结果,服务器也可以选择不支持分页。在这种情况下,响应中不得返回 next_batch 标记。

安全性注意事项

服务器只能返回用户有权限查看的结果。

客户端访客访问

有时,客户端无需在主服务器上完整注册账户或加入房间即可与房间进行交互是更为理想的。本模块规定了此类客户端应如何与服务器交互,以便以访客身份参与房间。

访客用户通过使用普通的注册接口从主服务器获取访问令牌,将 kind 参数指定为 guest。随后,他们可以像其他用户一样与客户端-服务器 API 进行交互,但如客户端行为子章节所述,仅能访问 API 的子集。主服务器可以选择是否允许本地用户的访客访问,但并不了解其他主服务器上的用户是否为访客。

访客用户也可以通过正常的 register 流程升级其账户,需额外指定一个 POST 参数 guest_access_token,其值为访客令牌。同时,他们还需指定 username 参数(即用户名本地部分),该参数在其他情况下为可选项。

本模块并未完全考虑联合互通(Federation);它依赖于单个主服务器正确遵守本模块设定的规则,而不是允许所有主服务器相互强制执行这些规则。

事件

m.room.guest_access


This event controls whether guest users are allowed to join rooms. If this event is absent, servers should act as if it is present and has the guest_access value “forbidden”.

Event type: State event
State key A zero-length string.

Content

Name Type Description
guest_access string

Required: Whether guests can join the room.

One of: [can_join, forbidden].

Examples

{
  "content": {
    "guest_access": "can_join"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.guest_access",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

访客账户允许通过以下 API 端点获取事件及相关媒体资源:

访客账户允许通过以下 API 端点发送事件:

访客账户允许通过以下 API 端点维护其自身账户:

访客账户允许通过以下 API 端点进行端到端加密操作:

服务器行为

服务器必须仅在房间内存在 m.room.guest_access 状态事件且其 guest_access 值为 can_join 时允许访客用户加入房间。如果 m.room.guest_access 事件被修改为不再允许访客加入,服务器必须将这些访客用户的 m.room.member 状态设置为 leave

安全性考量

每个主服务器自行管理其访客账户,身份是否为访客账户的信息不会在服务器之间传递。因此,参与房间的任何服务器都被信任能够正确执行本节列出的权限规定。

主服务器可以考虑在访客注册时启用如验证码等保护措施,以防止垃圾信息、拒绝服务(DoS)等攻击。

主服务器可能会对访客账户采取更严格的速率限制,尤其是针对发送状态事件的操作。

房间预览

有时,允许用户在未加入房间的情况下“旁听”并阅读房间中发布的消息,即为房间提供预览,是十分有用的功能。当与 访客访问 结合使用时,这一功能效果尤为明显。

房间预览通过 world_readable房间历史消息可见性 设置以及 GET /events 接口的特殊版本实现。

客户端行为

希望在未加入房间的情况下查看房间内容的客户端,应调用 GET /rooms/:room_id/initialSync,然后调用 GET /events。对于每一个希望查看的房间,客户端都需要并行执行此操作。

当然,客户端也可以调用其他接口,例如 GET /rooms/:room_id/messagesGET /search,以访问 /events 流以外的事件。

GET /_matrix/client/v3/events


This will listen for new events related to a particular room and return them to the caller. This will block until an event is received, or until the timeout is reached.

This API is the same as the normal /events endpoint, but can be called by users who have not joined the room.

Note that the normal /events endpoint has been deprecated. This API will also be deprecated at some point, but its replacement is not yet known.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
from string

The token to stream from. This token is either from a previous request to this API or from the initial sync API.

room_id string

The room ID for which events should be returned.

timeout integer

The maximum time in milliseconds to wait for an event.


Responses

Status Description
200 The events received, which may be none.
400 Bad pagination from parameter.

200 response

Name Type Description
chunk [Event]

An array of events.

end string

A token which correlates to the last value in chunk. This token should be used in the next request to /events.

start string

A token which correlates to the first value in chunk. This is usually the same token supplied to from=.

Event
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "body": "This is an example text message",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>This is an example text message</b>",
        "msgtype": "m.text"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!somewhere:over.the.rainbow",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "end": "s3457_9_0",
  "start": "s3456_9_0"
}

服务器行为

对于尚未加入房间的客户端,服务器仅需返回这些事件:在事件发生时,房间状态存在 m.room.history_visibility 状态事件,且其 history_visibility 值为 world_readable

安全性注意事项

客户端可以向用户展示房间处于 world_readable 状态时,可能会向未加入房间的用户显示消息。通过此模块无法判断是否确有未加入的访客用户实际查看了房间中的事件,也无法列举或统计正在“旁听”的用户数量。

房间标签

用户可以为房间添加标签。标签是带有命名空间的字符串,用于标记房间。一个房间可以有多个标签。标签仅对设置它们的用户可见,但会在该用户的所有设备之间同步。

事件

房间上的标签通过房间的 account_data 部分中的单个 m.tag 事件接收。m.tag 事件的内容包含一个 tags 键,其值是一个对象,将每个标签的名称映射到另一个对象。

与每个标签关联的 JSON 对象包含关于该标签的信息,例如如何对带有某一标签的房间进行排序。

排序信息通过 order 键给出,值为介于 0 到 1 之间的数字。数字比较时,0 会最先显示。因此,order0.2 的房间将显示在 order0.7 的房间之前。如果房间拥有某标签但未包含 order 键,则应排在具有该标签且含有 order 键的房间之后。

标签的名称不得超过 255 字节。

标签的命名空间定义如下:

  • m.* 命名空间保留用于 Matrix 协议中定义的标签。客户端必须忽略这一命名空间中自己不支持的标签。
  • u.* 命名空间保留给用户自定义的标签。u. 之后的字符串定义为该标签的显示名称。客户端不应从该命名空间的标签推断除显示名之外的含义。
  • 客户端或应用如果需使用特殊标签以实现高级功能,应参照 state key 方式使用命名空间,例如:tld.name.*
  • 任何以 tld.name.* 形式出现但与当前客户端命名空间不匹配的标签都应被忽略
  • 不符合上述规则的标签应被解释为来自 u.* 命名空间的用户标签,视为其名称前已被去掉 u.(即标签的名称直接作为显示名)。这些无命名空间的标签是出于历史原因而被支持。新标签应当使用上述定义的命名空间之一。

协议中列出了一些特殊的标签名称:以下标签被定义在 m.* 命名空间下:

  • m.favourite:用户收藏的房间。应当优先于其他房间显示。
  • m.lowpriority:应当低于其他房间显示优先级。
  • m.server_notice:用于标识服务器通知房间

m.tag


Informs the client of tags on a room.

Event type: Message event

Content

Name Type Description
tags {string: Tag}

The tags on the room and their contents.

Tag
Name Type Description
order number

A number in a range [0,1] describing a relative position of the room under the given tag.

Examples

{
  "content": {
    "tags": {
      "u.work": {
        "order": 0.9
      }
    }
  },
  "type": "m.tag"
}

客户端行为

GET /_matrix/client/v3/user/{userId}/rooms/{roomId}/tags


List the tags set by a user on a room.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to get tags for.

userId string

Required: The id of the user to get tags for. The access token must be authorized to make requests for this user ID.


Responses

Status Description
200 The list of tags for the user for the room.

200 response

Name Type Description
tags {string: Tag}
Tag
Name Type Description
order number

A number in a range [0,1] describing a relative position of the room under the given tag.

{
  "tags": {
    "m.favourite": {
      "order": 0.1
    },
    "u.Customers": {},
    "u.Work": {
      "order": 0.7
    }
  }
}

PUT /_matrix/client/v3/user/{userId}/rooms/{roomId}/tags/{tag}


Add a tag to the room.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to add a tag to.

tag string

Required: The tag to add.

userId string

Required: The id of the user to add a tag for. The access token must be authorized to make requests for this user ID.

Request body

Tag
Name Type Description
order number

A number in a range [0,1] describing a relative position of the room under the given tag.

Request body example

{
  "order": 0.25
}

Responses

Status Description
200 The tag was successfully added.

200 response

{}

DELETE /_matrix/client/v3/user/{userId}/rooms/{roomId}/tags/{tag}


Remove a tag from the room.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to remove a tag from.

tag string

Required: The tag to remove.

userId string

Required: The id of the user to remove a tag for. The access token must be authorized to make requests for this user ID.


Responses

Status Description
200 The tag was successfully removed.

200 response

{}

客户端配置

客户端可以在他们的主服务器上为其账户存储自定义配置数据。这些账户数据将在不同设备间同步,并且能够在特定设备上的多次安装之间保持持久性。用户只能查看其自己账户的账户数据。

账户数据可以是全局的,也可以限定在特定房间内。这里没有继承机制:如果某个 type 类型的数据在房间的账户数据中缺失,不会自动回退到同类型的全局账户数据。

事件

客户端通过 /sync 响应中的 account_data 部分接收账户数据事件。

这些事件也可以在 /events 响应中接收,或者作为房间 /sync 响应中的 account_data 部分收到。出现在 /events 中的 m.tag 事件会带有所对应房间的 room_id

客户端行为

GET /_matrix/client/v3/user/{userId}/account_data/{type}


Get some account data for the client. This config is only visible to the user that set the account data.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
type string

Required: The event type of the account data to get. Custom types should be namespaced to avoid clashes.

userId string

Required: The ID of the user to get account data for. The access token must be authorized to make requests for this user ID.


Responses

Status Description
200 The account data content for the given type.
403 The access token provided is not authorized to retrieve this user’s account data. Errcode: M_FORBIDDEN.
404 No account data has been provided for this user with the given type. Errcode: M_NOT_FOUND.

200 response

{
  "custom_account_data_key": "custom_config_value"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot add account data for other users."
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Account data not found."
}

PUT /_matrix/client/v3/user/{userId}/account_data/{type}


Set some account data for the client. This config is only visible to the user that set the account data. The config will be available to clients through the top-level account_data field in the homeserver response to /sync.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
type string

Required: The event type of the account data to set. Custom types should be namespaced to avoid clashes.

userId string

Required: The ID of the user to set account data for. The access token must be authorized to make requests for this user ID.

Request body

Request body example

{
  "custom_account_data_key": "custom_config_value"
}

Responses

Status Description
200 The account data was successfully added.
400 The request body is not a JSON object. Errcode: M_BAD_JSON or M_NOT_JSON.
403 The access token provided is not authorized to modify this user’s account data. Errcode: M_FORBIDDEN.
405 This type of account data is controlled by the server; it cannot be modified by clients. Errcode: M_BAD_JSON.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_JSON",
  "error": "Content must be a JSON object."
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot add account data for other users."
}

405 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_BAD_JSON",
  "error": "Cannot set m.fully_read through this API."
}

GET /_matrix/client/v3/user/{userId}/rooms/{roomId}/account_data/{type}


Get some account data for the client on a given room. This config is only visible to the user that set the account data.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to get account data for.

type string

Required: The event type of the account data to get. Custom types should be namespaced to avoid clashes.

userId string

Required: The ID of the user to get account data for. The access token must be authorized to make requests for this user ID.


Responses

Status Description
200 The account data content for the given type.
400 The given roomID is not a valid room ID. Errcode: M_INVALID_PARAM.
403 The access token provided is not authorized to retrieve this user’s account data. Errcode: M_FORBIDDEN.
404 No account data has been provided for this user and this room with the given type. Errcode: M_NOT_FOUND.

200 response

{
  "custom_account_data_key": "custom_config_value"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "@notaroomid:example.org is not a valid room ID."
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot add account data for other users."
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "Room account data not found."
}

PUT /_matrix/client/v3/user/{userId}/rooms/{roomId}/account_data/{type}


Set some account data for the client on a given room. This config is only visible to the user that set the account data. The config will be delivered to clients in the per-room entries via /sync.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to set account data on.

type string

Required: The event type of the account data to set. Custom types should be namespaced to avoid clashes.

userId string

Required: The ID of the user to set account data for. The access token must be authorized to make requests for this user ID.

Request body

Request body example

{
  "custom_account_data_key": "custom_account_data_value"
}

Responses

Status Description
200 The account data was successfully added.
400 The request body is not a JSON object (errcode M_BAD_JSON or M_NOT_JSON), or the given roomID is not a valid room ID (errcode M_INVALID_PARAM).
403 The access token provided is not authorized to modify this user’s account data. Errcode: M_FORBIDDEN.
405 This type of account data is controlled by the server; it cannot be modified by clients. Errcode: M_BAD_JSON.

200 response

{}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_JSON",
  "error": "Content must be a JSON object."
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "Cannot add account data for other users."
}

405 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_BAD_JSON",
  "error": "Cannot set m.fully_read through this API."
}

服务器行为

服务器必须拒绝设置服务器自身管理的事件类型的账户数据,并返回 405 错误响应。 目前,仅包括 m.fully_readm.push_rules 事件类型。这一规定同样适用于全局和按房间划分的账户数据。

[Changed in v1.10] m.push_rules 被添加到了拒绝列表中。

服务器必须允许客户端正常读取上述事件类型的数据。

服务器管理

该模块为服务器管理员增加了检查服务器状态和数据的能力。

客户端行为

GET /_matrix/client/v3/admin/whois/{userId}


Gets information about a particular user.

This API may be restricted to only be called by the user being looked up, or by a server admin. Server-local administrator privileges are not specified in this document.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user to look up.


Responses

Status Description
200 The lookup was successful.

200 response

Name Type Description
devices {string: DeviceInfo}

Each key is an identifier for one of the user’s devices.

user_id string

The Matrix user ID of the user.

DeviceInfo
Name Type Description
sessions [SessionInfo]

A user’s sessions (i.e. what they did with an access token from one login).

SessionInfo
Name Type Description
connections [ConnectionInfo]

Information particular connections in the session.

ConnectionInfo
Name Type Description
ip string

Most recently seen IP address of the session.

last_seen integer

Unix timestamp that the session was last active.

user_agent string

User agent string last seen in the session.

{
  "devices": {
    "teapot": {
      "sessions": [
        {
          "connections": [
            {
              "ip": "127.0.0.1",
              "last_seen": 1411996332123,
              "user_agent": "curl/7.31.0-DEV"
            },
            {
              "ip": "10.0.0.2",
              "last_seen": 1411996332123,
              "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36"
            }
          ]
        }
      ]
    }
  },
  "user_id": "@peter:rabbit.rocks"
}

事件上下文

该 API 返回发生在指定事件之前和之后的一系列事件。这样,客户端可以获取围绕某一事件的上下文信息。

客户端行为

用于检索事件上下文的 HTTP API 只有一个,具体文档如下。

GET /_matrix/client/v3/rooms/{roomId}/context/{eventId}


This API returns a number of events that happened just before and after the specified event. This allows clients to get the context surrounding an event.

Note: This endpoint supports lazy-loading of room member events. See Lazy-loading room members for more information.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The event to get context around.

roomId string

Required: The room to get events from.

query parameters
Name Type Description
filter string

A JSON RoomEventFilter to filter the returned events with. The filter is only applied to events_before, events_after, and state. It is not applied to the event itself. The filter may be applied before or/and after the limit parameter - whichever the homeserver prefers.

See Filtering for more information.

limit integer

The maximum number of context events to return. The limit applies to the sum of the events_before and events_after arrays. The requested event ID is always returned in event even if limit is 0. Defaults to 10.


Responses

Status Description
200 The events and state surrounding the requested event.

200 response

Name Type Description
end string

A token that can be used to paginate forwards with.

event ClientEvent

Details of the requested event.

events_after [ClientEvent]

A list of room events that happened just after the requested event, in chronological order.

events_before [ClientEvent]

A list of room events that happened just before the requested event, in reverse-chronological order.

start string

A token that can be used to paginate backwards with.

state [ClientEvent]

The state of the room at the last event returned.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "end": "t29-57_2_0_2",
  "event": {
    "content": {
      "body": "filename.jpg",
      "info": {
        "h": 398,
        "mimetype": "image/jpeg",
        "size": 31037,
        "w": 394
      },
      "msgtype": "m.image",
      "url": "mxc://example.org/JWEIFJgwEIhweiWJE"
    },
    "event_id": "$f3h4d129462ha:example.com",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "type": "m.room.message",
    "unsigned": {
      "age": 1234,
      "membership": "join"
    }
  },
  "events_after": [
    {
      "content": {
        "body": "This is an example text message",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>This is an example text message</b>",
        "msgtype": "m.text"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "events_before": [
    {
      "content": {
        "body": "something-important.doc",
        "filename": "something-important.doc",
        "info": {
          "mimetype": "application/msword",
          "size": 46144
        },
        "msgtype": "m.file",
        "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "start": "t27-54_2_0_2",
  "state": [
    {
      "content": {
        "m.federate": true,
        "predecessor": {
          "event_id": "$something:example.org",
          "room_id": "!oldroom:example.org"
        },
        "room_version": "11"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "",
      "type": "m.room.create",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    },
    {
      "content": {
        "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
        "displayname": "Alice Margatroid",
        "membership": "join",
        "reason": "Looking for support"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "@alice:example.org",
      "type": "m.room.member",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ]
}

安全注意事项

服务器只能返回用户有权限查看的结果。

SSO 客户端登录/认证

单点登录(Single Sign-On, SSO)是一个通用术语,指的是允许用户通过单一的基于 Web 的认证门户登录应用程序的协议。例如 OpenID Connect、“中央认证服务”(CAS)以及 SAML。

本模块允许 Matrix 主服务器将用户认证委托给支持这些协议之一的外部认证服务器。在此过程中,涉及三个系统:

  • 一个使用本规范定义的 API 的 Matrix 客户端,它试图将用户认证至 Matrix 主服务器。
  • 一个实现了本规范所定义 API 的 Matrix 主服务器,但其用户认证委托给了认证服务器。
  • 一个“认证服务器”,负责对用户进行认证。

本规范只关注 Matrix 客户端与主服务器之间的通信,与用于与认证服务器通信的 SSO 协议无关。不同的 Matrix 主服务器实现可能支持不同的 SSO 协议。

实现 SSO 流程的客户端和主服务器需要同时考虑 登录用户交互式认证。两个过程类似,但存在细微差异。

通常,SSO 系统要求在认证服务器上配置一个“回调”URI。用户完成认证后,浏览器会被重定向到该 URI。Matrix 主服务器的实现需提供合适的端点。例如,对于 CAS 认证,主服务器应为管理员提供配置 CAS 服务器及消费票据的 REST 端点的方法。

主服务器可以选择性地向用户显示多个可选的 SSO 选项,通常以多个“使用 $provider 登录”按钮的形式展示。这些被称为“身份提供者”(IdPs)。

客户端通过 SSO 登录

流程概述如下:

  1. Matrix 客户端调用 GET /login,以查询支持的登录类型,主服务器在响应中包含带有 "type": "m.login.sso" 的流程。
  2. 为发起 m.login.sso 登录类型,Matrix 客户端引导用户浏览器跳转至用户主服务器上的 /login/sso/redirect 端点。若用户选择了某个 identity_providers,则可能是该端点的 IdP 版本。
  3. 主服务器以 HTTP 重定向响应至 SSO 用户界面,浏览器跟随重定向。
  4. 认证服务器与主服务器交互,验证用户身份及其他认证信息,过程中可能涉及多次重定向。
  5. 浏览器被引导至客户端提供的 redirectUrl,并带有 loginToken 查询参数,供客户端登录使用。
  6. 客户端通过携带 typem.login.token/login 端点调用,用登录令牌换取访问令牌。

对于原生应用,1 至 4 步通常通过打开嵌入式 Web 视图实现。

流程如下图所示:

    Matrix 客户端                      Matrix 主服务器              认证服务器
        |                                   |                          |
        |-------------(0) GET /login------->|                          |
        |<-------------登录类型--------------|                          |
        |                                   |                          |
        |   Webview                         |                          |
        |      |                            |                          |
        |----->|                            |                          |
        |      |--(1) GET /login/sso/redirect-->|                       |
        |      |<---------(2) 302----------------|                      |
        |      |                            |                          |
        |      |<========(3) 认证流程==============>|                   |
        |      |                            |                          |
        |      |<--(4) 重定向到 redirectUrl--|                          |
        |<-----|                            |                          |
        |                                   |                          |
        |---(5) POST /login (携 login token)->|                         |
        |<-------------访问令牌---------------|                         |

在此规范的旧版 r0.4.0 版本 中,如果主服务器提供 m.login.cas 登录流程,则可以通过 CAS 认证。本规范废弃了 m.login.cas 的使用,转而推荐使用 m.login.sso,其过程相同,仅区别在于重定向端点:对于 m.login.cas,使用 /cas/redirect,对于 m.login.sso,使用 /sso/redirect(见下文)。其他端点保持一致。

m.login.sso flow schema


m.login.sso flow schema
Name Type Description
identity_providers [IdP]

Optional identity providers (IdPs) to present to the user. These would appear (typically) as distinct buttons for the user to interact with, and would map to the appropriate IdP-dependent redirect endpoint for that IdP.

type string

Required: The string m.login.sso

One of: [m.login.sso].

IdP
Name Type Description
brand string

Optional UI hint for what kind of common SSO provider is being described in this IdP. Matrix maintains a registry of identifiers in the matrix-spec repo to ensure clients and servers are aligned on major/common brands.

Clients should prefer the brand over the icon, when both are provided. Clients are not required to support any particular brand, including those in the registry, though are expected to be able to present any IdP based off the name/icon to the user regardless.

Unregistered brands are permitted using the Common Namespaced Identifier Grammar, though excluding the namespace requirements. For example, examplesso is a valid brand which is not in the registry but still permitted. Servers should be mindful that clients might not support their unregistered brand usage as intended by the server.

icon string

Optional mxc:// URI to provide an image/icon representing the IdP. Intended to be shown alongside the name if provided.

Clients SHOULD use the deprecated /download and /thumbnail endpoints to retrieve this media item because clients will not have an access token they can authenticate with yet. Servers SHOULD ensure media used for IdP icons is excluded from the freeze described by the Content Repository module’s Client Behaviour section.

This may be addressed in the future with proposals like MSC4148, or removed entirely through the transition to OIDC.

id string

Required: Opaque string chosen by the homeserver, uniquely identifying the IdP from other IdPs the homeserver might support. Should use the Opaque identifier Grammar.

name string

Required: Human readable description for the IdP, intended to be shown to the user.

Examples

{
  "identity_providers": [
    {
      "brand": "github",
      "id": "com.example.idp.github",
      "name": "GitHub"
    },
    {
      "icon": "mxc://example.com/abc123",
      "id": "com.example.idp.gitlab",
      "name": "GitLab"
    }
  ],
  "type": "m.login.sso"
}
客户端行为

客户端通过引导浏览器跳转至 /login/sso/redirect (或使用某个 identity_providers 时跳转至 /login/sso/redirect/{idpId}) 并携带适当的 redirectUrl 启动流程。认证成功后,浏览器将被重定向至该 redirectUrl

GET /_matrix/client/v3/login/sso/redirect


Added in v1.1

A web-based Matrix client should instruct the user’s browser to navigate to this endpoint in order to log in via SSO.

The server MUST respond with an HTTP redirect to the SSO interface, or present a page which lets the user select an IdP to continue with in the event multiple are supported by the server.

Rate-limited: No
Requires authentication: No

Request

Request parameters

query parameters
Name Type Description
redirectUrl string

Required: URI to which the user will be redirected after the homeserver has authenticated the user with SSO.


Responses

Status Description
302 A redirect to the SSO interface.

GET /_matrix/client/v3/login/sso/redirect/{idpId}


Added in v1.1

This endpoint is the same as /login/sso/redirect, though with an IdP ID from the original identity_providers array to inform the server of which IdP the client/user would like to continue with.

The server MUST respond with an HTTP redirect to the SSO interface for that IdP.

Rate-limited: No
Requires authentication: No

Request

Request parameters

path parameters
Name Type Description
idpId string

Required: The id of the IdP from the m.login.sso identity_providers array denoting the user’s selection.

query parameters
Name Type Description
redirectUrl string

Required: URI to which the user will be redirected after the homeserver has authenticated the user with SSO.


Responses

Status Description
302 A redirect to the SSO interface.
404 The IdP ID was not recognized by the server. The server is encouraged to provide a user-friendly page explaining the error given the user will be navigated to it.
安全注意事项
  1. 通过操控 redirectUrl 参数进行的 CSRF 攻击

    客户端应校验对 redirectUrl 的任何请求。攻击者可能伪造查询参数,导致跨站请求伪造(CSRF)攻击。

    例如,假设一个 Web 客户端托管于 https://client.example.com,希望在主服务器 服务器名称server.example.org 上发起 SSO 登录,其通过在 redirectUrl 查询参数中存储服务器名实现重定向: https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=server.example.org

    攻击者可能诱导受害者访问 https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=evil.com,导致客户端将登录令牌发送到攻击者控制的 evil.com

    为防范此类风险,客户端不得将状态(如登录主服务器的地址)存储于任何可能被外部进程修改的位置。

    状态应存储在 localStorage 或 Cookie 中。

  2. 为进一步安全,客户端应在 redirectUrl 中携带唯一标识符,并拒绝不含已知标识符的回调,以防未授权登录尝试和重放攻击。

服务器行为

服务器应注意,identity_providers 是可选的,较老的客户端可能无法正确解析该值。在这些情况下,客户端将使用通用的 /redirect 端点,而不是 /redirect/{idpId} 端点。

重定向到认证服务器

服务器应如下处理 /_matrix/client/v3/login/sso/redirect

  1. 构建适合 SSO 系统的请求。
  2. 存储足够的状态信息,以便在 SSO 流程完成后能够安全恢复流程。可通过为用户浏览器设置 Cookie 的方式完成,即在响应头中添加 Set-Cookie
  3. 将用户浏览器重定向到 SSO 登录页,并带上合适参数。

另请参见下方“安全注意事项”。

处理认证服务器回调

通常,会有一个回调 URI 同时用于登录与用户交互式认证,由主服务器实现区分当前流程。

主服务器应验证来自 SSO 系统的响应:这可能需要对认证服务器发起附加调用,和/或验证响应中的签名。

主服务器后续操作如下:

  1. 主服务器必须将认证服务器收到的用户详细信息映射为合法的 Matrix 用户标识符。可参见 其他字符集的映射 指南。
  2. 若生成的用户标识符为新用户,则应注册为新用户。
  3. 主服务器应生成一个短期登录令牌(login token)。这是一个不透明令牌,可用于以 m.login.token 类型调用 /login API。令牌有效期建议限制在五秒左右。
  4. 主服务器在最初的 /_matrix/client/v3/login/sso/redirect 请求所带的 redirectUrl 上,添加名为 loginToken 的查询参数,值为生成的登录令牌。(注意:redirectURL 可能含有已有的查询参数。若已存在一个或多个 loginToken 参数,应先移除后再添加新的。)
  5. 主服务器将浏览器重定向到构建完成的 URI。
安全注意事项
  1. 主服务器应确保登录令牌不会发送给恶意客户端。

    例如,假设主服务器为 server.example.org。攻击者诱导受害者点击 https://server.example.org/login/sso/redirect?redirectUrl=https://evil.com,结果导致登录令牌发送至攻击者控制的 evil.com,这属于 CSRF 攻击。

    为缓解风险,主服务器在处理 /_matrix/client/v3/login/sso/redirect 端点时,重定向到 SSO 登录页前或在认证服务器回调后,应征得用户同意,将 Matrix 账号的访问权限授予 redirectUrl 指定的站点。

    可以设置信任白名单,仅允许已知受信任的客户端 URL。主服务器自身的 登录回退 实现可排除在外。

  2. 为进一步安全,主服务器可追踪待处理请求,防止未授权认证。可通过在处理 /_matrix/client/v3/login/sso/redirect 时设置 Cookie,并在从认证服务器回调时校验并清除该 Cookie 实现。

用户交互式认证中的 SSO

用户交互式认证 适用于客户端-服务器端点,需要对用户身份进行额外确认(超出持有访问令牌以外)。通常情况下用户需要重新输入密码,但对于将认证委托给 SSO 服务器的主服务器,这意味着在用户交互式认证过程中重定向到认证服务器。

该实现基于用户交互式认证的 回退 机制。

客户端行为

客户端除确保实现回退机制,并将 m.login.sso 类型认作任意未知类型外,无需额外操作,即应为 /_matrix/client/v3/auth/m.login.sso/fallback/web?session=<session_id> 打开浏览器窗口。流程完成后,客户端仅携带 session 重新尝试请求。

服务器行为

重定向至认证服务器

服务器应以类似于 /_matrix/client/v3/login/sso/redirect 的方式处理 /_matrix/client/v3/auth/m.login.sso/fallback/web

  1. 构建适合 SSO 系统的请求。
  2. 存储足够的状态信息,以便在 SSO 流程完成后能够安全恢复流程。可通过为用户浏览器设置 Cookie 的方式实现,即在响应头设置 Set-Cookie
  3. 将用户浏览器重定向到 SSO 登录页,并携带适当参数。

另请参阅下方“安全注意事项”。

处理来自认证服务器的回调

通常,会有单一回调 URI 同时用于登录和用户交互式认证,由主服务器确定当前流程。

主服务器应对来自 SSO 系统的响应进行验证:这可能需要对认证服务器进行额外调用,和/或验证响应的签名。

随后主服务器向用户浏览器返回用户交互式认证回退完成页面。

安全注意事项
  1. 操作确认

    主服务器应确认用户同意继续操作。用户交互式认证的目标是防止被盗用的 access_token 用于接管用户账号。仅重定向到 SSO 系统远远不够,因为用户可能尚未意识到正在进行的操作,或 SSO 系统可能会自动确认认证。

    例如,主服务器可向用户展示类似如下内容的页面:

    某客户端正在尝试从您的账户移除设备。请通过单点登录重新认证以确认此操作。如果此操作并非您本人发起,请警惕您的账户可能被盗用!

    此操作确认可发生在重定向到 SSO 认证页前(处理 /_matrix/client/v3/auth/m.login.sso/fallback/web 端点时)、或认证服务器回调后。如果在认证前确认,尤其要防范下述未授权认证尝试。

  2. 为进一步安全,主服务器应追踪待处理请求,防止未授权认证。例如可在处理 /_matrix/client/v3/auth/m.login.sso/fallback/web 时设置 Cookie,并在认证服务器回调时校验并清除该 Cookie。

私信

Matrix 中的所有通信都发生在房间内。有时,用户希望能够直接与某一个特定的人交流。本模块定义了一种方法,可以将某些房间标记为与指定对象的“私聊”。这并不意味着聊天只能局限于两个人之间,因为这会排除自动“机器人”用户,或者“个人助手”等替用户在其不在时回复私信的功能。

一个房间未必会被房间内所有成员视为“私聊”,但存在一种信号机制,用于向被邀请人传递聊天是否为“私聊”的信息。

事件

m.direct


A map of which rooms are considered ‘direct’ rooms for specific users is kept in account_data in an event of type m.direct. The content of this event is an object where the keys are the user IDs and values are lists of room ID strings of the ‘direct’ rooms for that user ID.

Event type: Message event

Content

Type Description
{User ID: [string]}

The mapping of user ID to a list of room IDs of the ‘direct’ rooms for that user ID.

Examples

{
  "content": {
    "@bob:example.com": [
      "!abcdefgh:example.com",
      "!hgfedcba:example.com"
    ]
  },
  "type": "m.direct"
}

客户端行为

要与其他用户发起私聊,邀请方的客户端应在 /createRoom 时设置 is_direct 标志。当用户操作的流程意图是与某人直接交流,而不是邀请该人加入一个公共房间时,客户端都应设置该标志。例如,用户在某个人的头像旁点击“开始聊天”时,意味着应设置 is_direct 标志。

被邀请方的客户端可以利用 m.room.member 事件中的 is_direct 标志自动将该房间标记为私聊,但这不是强制要求:客户端也可以弹窗提示用户,或完全忽略该标志。

邀请人和被邀请人的客户端都应通过在账户数据中存储一个 m.direct 事件,将该房间记为私聊,接口为 /user/<user_id>/account_data/<type>

服务端行为

/createRoom 接口中提供了 is_direct 标志时,所属服务器必须在 /createRoom 调用所邀请成员的邀请事件中设置 is_direct 标志。

忽略用户

在通过 Matrix 进行通信时,您可能希望出于某些原因忽略特定用户。本模块定义了客户端和服务器如何实现对用户的忽略。

事件

m.ignored_user_list


A map of users which are considered ignored is kept in account_data in an event type of m.ignored_user_list.

Event type: Message event

Content

Name Type Description
ignored_users {User ID: object}

Required: The map of users to ignore. This is a mapping of user ID to empty object.

Examples

{
  "content": {
    "ignored_users": {
      "@someone:example.org": {}
    }
  },
  "type": "m.ignored_user_list"
}

客户端行为

若要忽略(实质上是屏蔽)某个用户,客户端应将目标用户添加至其账户数据中的 m.ignored_user_list 事件,使用 /user/<user_id>/account_data/<type> 完成操作。用户被忽略后,客户端将不再收到该用户发送的事件,状态事件除外。客户端应选择隐藏被新忽略用户之前发送的内容,或执行一次不带历史 token 的新 /sync

被忽略用户对新房间的邀请将不会发送给客户端。服务器也可以选择代表客户端拒绝该邀请。

即使用户被忽略,状态事件仍然会发送给客户端。这是为了确保某些部分(如房间名)不会因为用户被忽略而在客户端表现出不同。

要将某个用户从忽略列表中移除,只需从账户数据事件中移除该用户。服务器将恢复发送此前被忽略用户的事件,但不应发送用户被忽略期间错过的事件。若需接收到被忽略期间发送的事件,客户端应执行一次全新同步。客户端还可取消对之前因忽略该用户而隐藏的事件的隐藏。

服务器行为

m.ignored_user_list 更新后,所有客户端的同步 API 应立即开始忽略(或取消忽略)相关用户。客户端负责确定是隐藏已发送的事件,还是开启新的同步流。

服务器仍需向客户端发送被忽略用户发送的状态事件。

服务器不得将被忽略用户发起的房间邀请发送给客户端。服务器也可以选择拒绝该邀请。

贴纸消息

该模块允许用户在房间或直接消息会话中发送贴纸消息。

贴纸消息是一种特殊的图片消息,展示时不带有控件(例如,不会显示“下载”链接,或在点击时以灯箱方式显示,如 m.image 事件中所示)。

贴纸消息旨在在消息时间线上提供简单的“反馈”事件。Matrix 客户端应提供某种机制,以显示贴纸的“body”,例如在悬停时作为工具提示显示,或在点击贴纸图片时以弹窗形式展示。

事件

贴纸事件以单个 m.sticker 事件的形式,在房间的 timeline 部分,通过 /sync 接收。

m.sticker


This message represents a single sticker image.

Event type: Message event

Content

Name Type Description
body string

Required: A textual representation or associated description of the sticker image. This could be the alt text of the original image, or a message to accompany and further describe the sticker.

info ImageInfo

Required: Metadata about the image referred to in url including a thumbnail representation.

url string

Required: The URL to the sticker image. This must be a valid mxc:// URI.

ImageInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

thumbnail_file EncryptedFile

Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted.

thumbnail_info ThumbnailInfo

Metadata about the image referred to in thumbnail_url.

thumbnail_url string

The URL (typically mxc:// URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

ThumbnailInfo
Name Type Description
h integer

The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.

mimetype string

The mimetype of the image, e.g. image/jpeg.

size integer

Size of the image in bytes.

w integer

The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "Landing",
    "info": {
      "h": 200,
      "mimetype": "image/png",
      "size": 73602,
      "thumbnail_info": {
        "h": 200,
        "mimetype": "image/png",
        "size": 73602,
        "w": 140
      },
      "thumbnail_url": "mxc://matrix.org/sHhqkFCvSkFwtmvtETOtKnLP",
      "w": 140
    },
    "url": "mxc://matrix.org/sHhqkFCvSkFwtmvtETOtKnLP"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.sticker",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

支持此消息类型的客户端应直接在时间线中展示事件 URL 指向的图片内容。

应在 info 对象中提供缩略图图片。这主要是为那些尚未完全支持 m.sticker 事件类型的客户端提供的降级方案。在大多数情况下,将缩略图 URL 设为与主事件内容相同的 URL 即可。

建议贴纸图片内容的大小为 512x512 像素或更小。图片文件的尺寸应为 info 对象中指定的理想展示尺寸的两倍,以便在高 DPI 屏幕上渲染更清晰的图像。

举报内容

用户可能会遇到他们认为不适当的内容,并且应当能够将其举报给服务器管理员或房间管理员进行审核。本模块定义了用户举报内容的方法。

客户端行为

POST /_matrix/client/v3/rooms/{roomId}/report


Added in v1.13

Reports a room as inappropriate to the server, which may then notify the appropriate people. How such information is delivered is left up to implementations. The caller is not required to be joined to the room to report it.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room being reported.

Request body

Name Type Description
reason string

Required: The reason the room is being reported. May be blank.

Request body example

{
  "reason": "this makes me sad"
}

Responses

Status Description
200 The room has been reported successfully.
404 The room was not found on the homeserver.
429 This request was rate-limited.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The room was not found."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}


Changed in v1.8: This endpoint now requires the user to be joined to the room.

Reports an event as inappropriate to the server, which may then notify the appropriate people. The caller must be joined to the room to report it.

Furthermore, it might be possible for clients to deduce whether a reported event exists by timing the response. This is because only a report for an existing event will require the homeserver to do further processing. To combat this, homeservers MAY add a random delay when generating a response.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
eventId string

Required: The event to report.

roomId string

Required: The room in which the event being reported is located.

Request body

Name Type Description
reason string

The reason the content is being reported.

score integer

The score to rate this content as where -100 is most offensive and 0 is inoffensive.

Request body example

{
  "reason": "this makes me sad",
  "score": -100
}

Responses

Status Description
200 The event has been reported successfully.
404

The event was not found or you are not joined to the room where the event resides.

Homeserver implementations can additionally return this error if the reported event has been redacted.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The event was not found or you are not joined to the room."
}

POST /_matrix/client/v3/users/{userId}/report


Added in v1.14

Reports a user as inappropriate to the server, which may then notify the appropriate people. How such information is delivered is left up to implementations. The caller is not required to be joined to any rooms that the reported user is joined to.

Clients may wish to ignore users after reporting them.

Clients could infer whether a reported user exists based on the 404 response. Homeservers that wish to conceal this information MAY return 200 responses regardless of the existence of the reported user.

Furthermore, it might be possible for clients to deduce whether a reported user exists by timing the response. This is because only a report for an existing user will require the homeserver to do further processing. To combat this, homeservers MAY add a random delay when generating a response.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId User ID

Required: The user being reported.

Request body

Name Type Description
reason string

Required: The reason the room is being reported. May be blank.

Request body example

{
  "reason": "this makes me sad"
}

Responses

Status Description
200 The user has been reported successfully or the server chose to not disclose whether the users exists.
404 The user was not found on the homeserver.
429 This request was rate-limited.

200 response

{}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND",
  "error": "The user was not found."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

服务器行为

服务器可以以任何他们认为合适的方式处理被举报的内容。这可能包括专用的房间,用于提醒服务器管理员有关被举报内容的信息,或者其他通知相关人员的机制。

尤其是在有害内容爆发期间,用户可能会举报整个房间而不仅仅是单个事件。因此,服务器管理员和安全团队在处理举报时,应当谨慎,避免关闭那些可能本身是合法的房间。

[Changed in v1.8] 在处理事件举报时,服务器在接受举报前必须验证举报用户当前已加入该事件所在的房间。

[Added in v1.13] 相反,服务器不得根据举报用户是否已加入房间来限制对房间的举报。这是因为用户即使未加入房间,也可能会接触到有害内容。例如,通过房间目录或邀请等途径。

[Added in v1.14] 同样,服务器不得根据举报用户是否已加入被举报用户所在的任意房间来限制对用户的举报。这是因为用户即使未加入房间,也可能会接触到有害内容。例如,通过用户目录或邀请等途径。

第三方网络

应用服务可以通过桥接提供对第三方网络的访问。这使得 Matrix 用户能够与其他通信平台上的用户进行交流,消息由应用服务在双方之间传递。单个应用服务可以桥接多个第三方网络,以及这些网络中的许多具体位置。单个第三方网络位置可以桥接到多个 Matrix 房间。

第三方查找

客户端可能希望为加入第三方位置和连接第三方用户提供丰富的界面。实现此类界面所需的信息由第三方查找功能提供。

GET /_matrix/client/v3/thirdparty/location


Retrieve an array of third-party network locations from a Matrix room alias.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
alias string

Required: The Matrix room alias to look up.


Responses

Status Description
200 All found third-party locations.
404 The Matrix room alias was not found

200 response

Array of Location.

Location
Name Type Description
alias string

Required: An alias for a matrix room.

fields object

Required: Information used to identify this third-party location.

protocol string

Required: The protocol ID that the third-party location is a part of.

[
  {
    "alias": "#freenode_#matrix:matrix.org",
    "fields": {
      "channel": "#matrix",
      "network": "freenode"
    },
    "protocol": "irc"
  }
]

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND"
}

GET /_matrix/client/v3/thirdparty/location/{protocol}


Requesting this endpoint with a valid protocol name results in a list of successful mapping results in a JSON array. Each result contains objects to represent the Matrix room or rooms that represent a portal to this third-party network. Each has the Matrix room alias string, an identifier for the particular third-party network protocol, and an object containing the network-specific fields that comprise this identifier. It should attempt to canonicalise the identifier as much as reasonably possible given the network type.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
protocol string

Required: The protocol used to communicate to the third-party network.

query parameters
Name Type Description
fields {string: string}

One or more custom fields to help identify the third-party location.


Responses

Status Description
200 At least one portal room was found.
404 No portal rooms were found.

200 response

Array of Location.

Location
Name Type Description
alias string

Required: An alias for a matrix room.

fields object

Required: Information used to identify this third-party location.

protocol string

Required: The protocol ID that the third-party location is a part of.

[
  {
    "alias": "#freenode_#matrix:matrix.org",
    "fields": {
      "channel": "#matrix",
      "network": "freenode"
    },
    "protocol": "irc"
  }
]

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND"
}

GET /_matrix/client/v3/thirdparty/protocol/{protocol}


Fetches the metadata from the homeserver about a particular third-party protocol.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
protocol string

Required: The name of the protocol.


Responses

Status Description
200 The protocol was found and metadata returned.
404 The protocol is unknown.

200 response

Protocol
Name Type Description
field_types {string: Field Type}

Required: The type definitions for the fields defined in user_fields and location_fields. Each entry in those arrays MUST have an entry here. The string key for this object is the field name itself.

May be an empty object if no fields are defined.

icon string

Required: A content URI representing an icon for the third-party protocol.

instances [Protocol Instance]

Required: A list of objects representing independent instances of configuration. For example, multiple networks on IRC if multiple are provided by the same application service.

The instances are modified by the homeserver from the response of GET /_matrix/app/v1/thirdparty/protocol/{protocol} to include an instance_id to serve as a unique identifier for each instance on the homeserver.

location_fields [string]

Required: Fields which may be used to identify a third-party location. These should be ordered to suggest the way that entities may be grouped, where higher groupings are ordered first. For example, the name of a network should be searched before the name of a channel.

user_fields [string]

Required: Fields which may be used to identify a third-party user. These should be ordered to suggest the way that entities may be grouped, where higher groupings are ordered first. For example, the name of a network should be searched before the nickname of a user.

Field Type
Name Type Description
placeholder string

Required: A placeholder serving as a valid example of the field value.

regexp string

Required: A regular expression for validation of a field’s value. This may be relatively coarse to verify the value as the application service providing this protocol may apply additional validation or filtering.

Protocol Instance
Name Type Description
desc string

Required: A human-readable description for the protocol, such as the name.

fields object

Required: Preset values for fields the client may use to search by.

icon string

An optional content URI representing the protocol. Overrides the one provided at the higher level Protocol object.

instance_id string

A unique identifier for this instance on the homeserver. This field is added to the response of GET /_matrix/app/v1/thirdparty/protocol/{protocol} by the homeserver.

This is the identifier to use as the third_party_instance_id in a request to POST /_matrix/client/v3/publicRooms.

network_id string

Required: A unique identifier across all instances.

{
  "field_types": {
    "channel": {
      "placeholder": "#foobar",
      "regexp": "#[^\\s]+"
    },
    "network": {
      "placeholder": "irc.example.org",
      "regexp": "([a-z0-9]+\\.)*[a-z0-9]+"
    },
    "nickname": {
      "placeholder": "username",
      "regexp": "[^\\s#]+"
    }
  },
  "icon": "mxc://example.org/aBcDeFgH",
  "instances": [
    {
      "desc": "Freenode",
      "fields": {
        "network": "freenode"
      },
      "icon": "mxc://example.org/JkLmNoPq",
      "instance_id": "irc-freenode",
      "network_id": "freenode"
    }
  ],
  "location_fields": [
    "network",
    "channel"
  ],
  "user_fields": [
    "network",
    "nickname"
  ]
}

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND"
}

GET /_matrix/client/v3/thirdparty/protocols


Fetches the overall metadata about protocols supported by the homeserver. Includes both the available protocols and all fields required for queries against each protocol.

Rate-limited: No
Requires authentication: Yes

Request

No request parameters or request body.


Responses

Status Description
200 The protocols supported by the homeserver.

200 response

Type Description
{string: Protocol}

Dictionary of supported third-party protocols.

Protocol
Name Type Description
field_types {string: Field Type}

Required: The type definitions for the fields defined in user_fields and location_fields. Each entry in those arrays MUST have an entry here. The string key for this object is the field name itself.

May be an empty object if no fields are defined.

icon string

Required: A content URI representing an icon for the third-party protocol.

instances [Protocol Instance]

Required: A list of objects representing independent instances of configuration. For example, multiple networks on IRC if multiple are provided by the same application service.

The instances are modified by the homeserver from the response of GET /_matrix/app/v1/thirdparty/protocol/{protocol} to include an instance_id to serve as a unique identifier for each instance on the homeserver.

location_fields [string]

Required: Fields which may be used to identify a third-party location. These should be ordered to suggest the way that entities may be grouped, where higher groupings are ordered first. For example, the name of a network should be searched before the name of a channel.

user_fields [string]

Required: Fields which may be used to identify a third-party user. These should be ordered to suggest the way that entities may be grouped, where higher groupings are ordered first. For example, the name of a network should be searched before the nickname of a user.

Field Type
Name Type Description
placeholder string

Required: A placeholder serving as a valid example of the field value.

regexp string

Required: A regular expression for validation of a field’s value. This may be relatively coarse to verify the value as the application service providing this protocol may apply additional validation or filtering.

Protocol Instance
Name Type Description
desc string

Required: A human-readable description for the protocol, such as the name.

fields object

Required: Preset values for fields the client may use to search by.

icon string

An optional content URI representing the protocol. Overrides the one provided at the higher level Protocol object.

instance_id string

A unique identifier for this instance on the homeserver. This field is added to the response of GET /_matrix/app/v1/thirdparty/protocol/{protocol} by the homeserver.

This is the identifier to use as the third_party_instance_id in a request to POST /_matrix/client/v3/publicRooms.

network_id string

Required: A unique identifier across all instances.

{
  "gitter": {
    "field_types": {
      "room": {
        "placeholder": "matrix-org/matrix-doc",
        "regexp": "[^\\s]+\\/[^\\s]+"
      },
      "username": {
        "placeholder": "@username",
        "regexp": "@[^\\s]+"
      }
    },
    "instances": [
      {
        "desc": "Gitter",
        "fields": {},
        "icon": "mxc://example.org/zXyWvUt",
        "instance_id": "gitter-gitter",
        "network_id": "gitter"
      }
    ],
    "location_fields": [
      "room"
    ],
    "user_fields": [
      "username"
    ]
  },
  "irc": {
    "field_types": {
      "channel": {
        "placeholder": "#foobar",
        "regexp": "#[^\\s]+"
      },
      "network": {
        "placeholder": "irc.example.org",
        "regexp": "([a-z0-9]+\\.)*[a-z0-9]+"
      },
      "nickname": {
        "placeholder": "username",
        "regexp": "[^\\s]+"
      }
    },
    "icon": "mxc://example.org/aBcDeFgH",
    "instances": [
      {
        "desc": "Freenode",
        "fields": {
          "network": "freenode.net"
        },
        "icon": "mxc://example.org/JkLmNoPq",
        "instance_id": "irc-freenode",
        "network_id": "freenode"
      }
    ],
    "location_fields": [
      "network",
      "channel"
    ],
    "user_fields": [
      "network",
      "nickname"
    ]
  }
}

GET /_matrix/client/v3/thirdparty/user


Retrieve an array of third-party users from a Matrix User ID.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

query parameters
Name Type Description
userid string

Required: The Matrix User ID to look up.


Responses

Status Description
200 An array of third-party users.
404 The Matrix User ID was not found.

200 response

Array of User.

User
Name Type Description
fields object

Required: Information used to identify this third-party location.

protocol string

Required: The protocol ID that the third-party location is a part of.

userid string

Required: A Matrix User ID representing a third-party user.

[
  {
    "fields": {
      "user": "jim"
    },
    "protocol": "gitter",
    "userid": "@_gitter_jim:matrix.org"
  }
]

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND"
}

GET /_matrix/client/v3/thirdparty/user/{protocol}


Retrieve a Matrix User ID linked to a user on the third-party service, given a set of user parameters.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
protocol string

Required: The name of the protocol.

query parameters
Name Type Description
fields {string: string}

One or more custom fields that are passed to the AS to help identify the user.


Responses

Status Description
200 The Matrix User IDs found with the given parameters.
404 The Matrix User ID was not found.

200 response

Array of User.

User
Name Type Description
fields object

Required: Information used to identify this third-party location.

protocol string

Required: The protocol ID that the third-party location is a part of.

userid string

Required: A Matrix User ID representing a third-party user.

[
  {
    "fields": {
      "user": "jim"
    },
    "protocol": "gitter",
    "userid": "@_gitter_jim:matrix.org"
  }
]

404 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_NOT_FOUND"
}

OpenID

该模块允许用户通过第三方服务验证其身份。第三方服务需要具备 Matrix 兼容性,即需要能够解析 Matrix 主服务器以便用用户的令牌交换身份信息。

POST /_matrix/client/v3/user/{userId}/openid/request_token


Gets an OpenID token object that the requester may supply to another service to verify their identity in Matrix. The generated token is only valid for exchanging for user information from the federation API for OpenID.

The access token generated is only valid for the OpenID API. It cannot be used to request another OpenID access token or call /sync, for example.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
userId string

Required: The user to request an OpenID token for. Should be the user who is authenticated for the request.

Request body

Request body example

{}

Responses

Status Description
200 OpenID token information. This response is nearly compatible with the response documented in the OpenID Connect 1.0 Specification with the only difference being the lack of an id_token. Instead, the Matrix homeserver’s name is provided.
429 This request was rate-limited.

200 response

OpenIdCredentials
Name Type Description
access_token string

Required: An access token the consumer may use to verify the identity of the person who generated the token. This is given to the federation API GET /openid/userinfo to verify the user’s identity.

expires_in integer

Required: The number of seconds before this token expires and a new one must be generated.

matrix_server_name string

Required: The homeserver domain the consumer should use when attempting to verify the user’s identity.

token_type string

Required: The string Bearer.

{
  "access_token": "SomeT0kenHere",
  "expires_in": 3600,
  "matrix_server_name": "example.com",
  "token_type": "Bearer"
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

房间的服务器访问控制列表(ACLs)

在某些场景下,房间管理员可能希望阻止恶意或不受信任的服务器参与他们的房间。向房间发送一个 m.room.server_acl 状态事件,是在联邦层面上阻止服务器参与房间的有效方法。

服务器 ACL 也可用于使房间仅与有限的服务器集合联邦,或事后让房间不再与任何其他服务器联邦,这类似于在 m.room.create 事件中设置 m.federate 值。

m.room.server_acl


An event to indicate which servers are permitted to participate in the room. Server ACLs may allow or deny groups of hosts. All servers participating in the room, including those that are denied, are expected to uphold the server ACL. Servers that do not uphold the ACLs MUST be added to the denied hosts list in order for the ACLs to remain effective.

The allow and deny lists are lists of glob-style patterns. When comparing against the server ACLs, the suspect server’s port number must not be considered. Therefore evil.com, evil.com:8448, and evil.com:1234 would all match rules that apply to evil.com, for example.

The ACLs are applied to servers when they make requests, and are applied in the following order:

  1. If there is no m.room.server_acl event in the room state, allow.
  2. If the server name is an IP address (v4 or v6) literal, and allow_ip_literals is present and false, deny.
  3. If the server name matches an entry in the deny list, deny.
  4. If the server name matches an entry in the allow list, allow.
  5. Otherwise, deny.

Note: Server ACLs do not restrict the events relative to the room DAG via authorisation rules, but instead act purely at the network layer to determine which servers are allowed to connect and interact with a given room.

Warning: Failing to provide an allow rule of some kind will prevent all servers from participating in the room, including the sender. This renders the room unusable. A common allow rule is [ "*" ] which would still permit the use of the deny list without losing the room.

Warning: All compliant servers must implement server ACLs. However, legacy or noncompliant servers exist which do not uphold ACLs, and these MUST be manually appended to the denied hosts list when setting an ACL to prevent them from leaking events from banned servers into a room. Currently, the only way to determine noncompliant hosts is to check the prev_events of leaked events, therefore detecting servers which are not upholding the ACLs. Server versions can also be used to try to detect hosts that will not uphold the ACLs, although this is not comprehensive. Server ACLs were added in Synapse v0.32.0, although other server implementations and versions exist in the world.

Event type: State event
State key A zero-length string.

Content

Name Type Description
allow [string]

The server names to allow in the room, excluding any port information. Each entry is interpreted as a glob-style pattern.

This defaults to an empty list when not provided, effectively disallowing every server.

allow_ip_literals boolean

True to allow server names that are IP address literals. False to deny. Defaults to true if missing or otherwise not a boolean.

This is strongly recommended to be set to false as servers running with IP literal names are strongly discouraged in order to require legitimate homeservers to be backed by a valid registered domain name.

deny [string]

The server names to disallow in the room, excluding any port information. Each entry is interpreted as a glob-style pattern.

This defaults to an empty list when not provided.

Examples

{
  "content": {
    "allow": [
      "*"
    ],
    "allow_ip_literals": false,
    "deny": [
      "*.evil.com",
      "evil.com"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.server_acl",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

端口号不受支持,因为解析器无法确定应该匹配端口号还是 IP 地址字面量。此外,几乎不会有人只信任某个域上的特定端口而不信任其他端口,尤其是考虑到服务器主机可以轻易更换端口。

CIDR 表示法不支持 IP 地址,因为 Matrix 并不鼓励使用 IP 作为服务器的身份标识。相反,提供了一个通用的 allow_ip_literals 选项用于全面禁止它们。

客户端行为

客户端除了发送该事件外,无需执行任何额外操作。客户端应在用户界面中描述对服务器 ACL 的更改,例如在时间线上展示。

客户端可以选择在拒绝服务器访问房间之前,先踢出受影响的用户,以帮助防止这些服务器参与,并向用户提供被排除在房间之外的反馈。

服务器行为

当房间状态中存在 m.room.server_acl 事件时,服务器必须阻止被列入黑名单的服务器发送事件或参与房间。具体受影响的 API,在服务器-服务器 API 规范中有详细说明。

如果被拒绝的服务器仍然是房间成员,服务器仍应向其发送事件。

安全性考量

服务器 ACL 只有在房间内的每个服务器都遵守它们时才有效。不遵守 ACL 的服务器仍可能允许被拒绝服务器发送的事件进入房间,并将其泄露给房间内的其他服务器。要在房间有效执行 ACL,还应在房间内拒绝那些不遵守 ACL 的服务器。

用户和房间提及

[Changed in v1.7]

本模块允许用户在房间事件中“提及”其他用户和房间。 这主要用于指示收件人应接收到关于该事件的通知。 通过在事件的 m.mentions 内容属性中包含元数据以引用被提及的实体来实现这一点。

m.mentions 的定义如下:

m.mentions


Describes whether the event mentions other users or the room. This is contained within the event’s content alongside other fields for the relevant event type.

m.mentions
Name Type Description
room boolean

A boolean set to true to mention the room, for an @room notification. (room should otherwise not be included on the event.)

user_ids [string]

A list of Matrix IDs of mentioned users.

Examples

{
  "user_ids": [
    "@alice:example.org"
  ]
}

一个事件的内容示例如下:

{
    "body": "Hello Alice!",
    "msgtype": "m.text",
    "format": "org.matrix.custom.html",
    "formatted_body": "Hello <a href='https://matrix.to/#/@alice:example.org'>Alice</a>!",
    "m.mentions": {
        "user_ids": ["@alice:example.org"]
    }
}

此外,请参阅 .m.rule.is_user_mention.m.rule.is_room_mention 推送规则。 用户不应将自己的 Matrix ID 添加到 m.mentions 属性中,因为发出的消息无法对本人进行通知。

如果加密事件的载荷中包含 m.mentions,应像普通内容一样进行加密。为正确处理加密房间中的提及,必须首先对事件进行解密。参见接收通知

请注意,为了向后兼容,像 .m.rule.contains_display_name.m.rule.contains_user_name.m.rule.roomnotif 这样的推送规则,仍将在事件的 body 包含用户显示名或 ID 时匹配。为避免无意的通知,建议客户端在每个事件中都包含一个 m.mentions 属性。(若无提及内容,可为一个空对象。)

在以往的规范版本中,用户提及是通过在事件明文 body 中包含用户的显示名或其 Matrix ID localpart 实现的,而房间提及则是包含字符串“@room”。这种方式容易导致混乱和 bug。

客户端行为

虽然可以悄悄地提及用户,但推荐在 m.room.message 事件的 HTML 正文中包含一个 Matrix URI。这仅适用于 msgtypem.textm.emotem.noticem.room.message 事件。事件的 format 必须为 org.matrix.custom.html,因此需要有 formatted_body

客户端在向即将发送的事件中添加用于提及的 Matrix URI 时,应遵循以下准则:

  • 当链接到用户时,在锚文本中显示用户可能存在歧义的显示名。若用户无显示名,则使用用户的 ID。
  • 当链接到房间时,使用该房间的规范别名(canonical alias)。若房间无规范别名,则优先使用房间上列出的别名之一。若找不到任何别名,则退回到房间 ID。在所有情况下,锚文本应为所链接的别名或房间 ID。

锚文本部分应在事件的 body 中用于原本表示该链接的位置,如上例所示。

客户端应将提及与其他元素区分开来。例如,可以通过改变提及的背景色以突出其与普通链接的不同。

如果当前用户在消息中被提及,客户端应将此提及以不同于其他提及的方式显示,例如使用红色背景以提醒用户本人被提及。请注意,用户可能会被提及但事件中未包含其 Matrix URI

点击提及时,应导航到相应的用户或房间信息。

房间升级

有时,由于各种原因,房间可能需要升级为不同的房间版本。本模块定义了一种在需要时将房间升级到不同房间版本的方法。

事件

m.room.tombstone


A state event signifying that a room has been upgraded to a different room version, and that clients should go there.

Event type: State event
State key A zero-length string.

Content

Name Type Description
body string

Required: A server-defined message.

replacement_room string

Required: The room ID of the new room the client should be visiting.

Examples

{
  "content": {
    "body": "This room has been replaced",
    "replacement_room": "!newroom:example.org"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.tombstone",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

能够识别 m.room.tombstone 事件及 m.room.create 事件中的 predecessor 字段的客户端,应向用户传达房间已升级的信息。一种实现方式是将旧房间从用户的房间列表中隐藏,并显示横幅,在新旧房间间提供相互链接——确保在引用旧房间时永久链接仍能正常工作。另一种做法是虚拟合并房间,使旧房间的时间线能够无缝延续到新房间的时间线,用户无需在房间间切换即可继续体验。

POST /_matrix/client/v3/rooms/{roomId}/upgrade


Upgrades the given room to a particular room version.

Rate-limited: No
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The ID of the room to upgrade.

Request body

Name Type Description
new_version string

Required: The new version for the room.

Request body example

{
  "new_version": "2"
}

Responses

Status Description
200 The room was successfully upgraded.
400 The request was invalid. One way this can happen is if the room version requested is not supported by the homeserver.
403 The user is not permitted to upgrade the room.

200 response

Name Type Description
replacement_room string

Required: The ID of the new room.

{
  "replacement_room": "!newroom:example.org"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_UNSUPPORTED_ROOM_VERSION",
  "error": "This server does not support that room version"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You cannot upgrade this room"
}

服务器行为

当客户端请求将已知房间升级为已知版本时,服务器应:

  1. 检查用户有权限在房间中发送 m.room.tombstone 事件。

  2. [Changed in v1.4] 创建一个替代房间,并在新房间中发送包含 predecessor 字段、相应 room_version 以及从前置房间复制的 type 字段的 m.room.create 事件。如果前一个房间未设置 type,则新房间的创建事件同样不指定 type

  3. 将可转移的状态事件复制到新房间。具体转移哪些内容留给实现方决定,不过推荐转移的状态事件包括:

    • m.room.server_acl
    • m.room.encryption
    • m.room.name
    • m.room.avatar
    • m.room.topic
    • m.room.guest_access
    • m.room.history_visibility
    • m.room.join_rules
    • m.room.power_levels

    会员事件不应用于转移到新房间,这是因为服务器在技术上无法冒充来自其他主服务器的用户。此外,服务器也不应转移对发送者有敏感要求的状态事件,例如 Matrix 命名空间之外的事件,客户端可能要求这些事件的发送者满足特定条件。

  4. 将所有本地别名迁移到新房间。

  5. 向旧房间发送 m.room.tombstone 事件,以指示该房间不再建议继续使用。

  6. 如有可能,还应修改旧房间的权限级别(power levels),以阻止发送事件和邀请新用户。例如,将 events_defaultinvite 设置为 50users_default + 1 中的较大者。

当用户加入新房间时,服务器应自动转移或复制用户的一些个性化设置,如通知、标签等。

服务器通知

Homeserver 提供商通常希望以官方身份向用户发送消息,或者其资源限制会影响用户使用 homeserver 的能力。例如,homeserver 可能每月只允许一定数量的活跃用户,并且已经超出了该限制。为了向用户传达这一限制,homeserver 会使用服务器通知房间(Server Notices Room)。

房间的外观(名称、主题、头像等)作为实现细节留给实现方决定。建议 homeserver 对房间进行装饰,使其在用户看来像是一个官方房间。

事件

通知会作为正常的 m.room.message 事件发送到客户端,在服务器通知房间内的事件 msgtypem.server_notice。客户端必须忽略服务器通知房间外,msgtypem.server_notice 的事件。

server_notice_type 的指定取值如下:

m.server_notice.usage_limit_reached
服务器已超出某项限制,需要服务器管理员进行干预。limit_type 描述已达成的限制类型。limit_type 的指定取值如下:

monthly_active_user
服务器在过去 30 天内的活跃用户数已超过最大值。服务器正在拒绝新的连接。“活跃”的定义作为实现细节留给实现方决定,但建议服务器将同步用户视为“活跃”。

m.room.messagemsgtype: m.server_notice


Represents a server notice for a user.

Event type: Message event

Content

Name Type Description
admin_contact string

A URI giving a contact method for the server administrator. Required if the notice type is m.server_notice.usage_limit_reached.

body string

Required: A human-readable description of the notice.

limit_type string

The kind of usage limit the server has exceeded. Required if the notice type is m.server_notice.usage_limit_reached.

msgtype string

Required:

One of: [m.server_notice].

server_notice_type string

Required: The type of notice being represented.

Examples

{
  "content": {
    "admin_contact": "mailto:server.admin@example.org",
    "body": "Human-readable message to explain the notice",
    "limit_type": "monthly_active_user",
    "msgtype": "m.server_notice",
    "server_notice_type": "m.server_notice.usage_limit_reached"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

客户端可以通过房间的 m.server_notice 标签识别服务器通知房间。活跃通知通过服务器通知房间中的置顶事件表示。在该房间中被置顶的服务器通知事件,客户端应通过特殊的用户界面展示给用户,而不是通过普通的置顶事件界面。例如,客户端可以显示警告横幅或弹窗以引起用户注意。在服务器通知房间中被置顶但不是服务器通知事件的事件,应与房间中其他置顶事件一样展示。

客户端不得期望能够拒绝加入服务器通知房间的邀请。尝试拒绝该邀请必须导致返回 M_CANNOT_LEAVE_SERVER_NOTICE_ROOM 错误。服务器不应阻止用户在加入服务器通知房间后离开该房间,但如果服务器要阻止离开房间,则必须使用同样的错误码。

服务器行为

服务器应为每个用户管理正好 1 个服务器通知房间。服务器必须通过 m.server_notice 标签向客户端标识此房间。服务器应向目标用户发送邀请,而不是自动将其加入服务器通知房间。

服务器如何向客户端发送通知、以及使用哪个用户发送事件,均作为服务器的实现细节处理。

内容审核策略列表

Matrix 作为一个开放网络,任何人都可以参与,因而存在着种类极为丰富的内容。让用户有权选择希望看到的内容以及想要屏蔽的内容显得尤为重要。进一步来说,房间管理员和服务器管理员同样应当能够选择他们不希望在其房间和服务器中托管的内容。

协议对此持中立立场:它不应为任何特定实体判断哪些内容为不当内容,而应赋权这些实体自行做出决策。因此,这里描述了一套通用框架,用于传递“内容审核策略列表”或“内容审核策略房间”。需要注意的是,本模块仅描述数据结构,而不涉及如何解读它们:决定过滤内容的实体最适合根据自身需求解读这些规则。

内容审核策略列表以房间状态事件的形式存储。对于房间的配置没有任何限制(可以是公开、私有、加密等)。

目前有三类实体可能会被规则影响:user(用户)、server(服务器)和 room(房间)。三者均以 m.policy.rule.<kind> 状态事件进行描述。策略规则的 state_key 是由规则发送者自定义的任意字符串。

规则包含关于为何制定此规则的建议及原因。reason 是描述 recommendation 的、供人阅读的字符串。目前,仅定义了一个建议类型——m.ban

m.ban 建议

当使用此建议时,应尽可能禁止规则中所影响的实体参与活动。其执行方式特意作为实现细节留给开发者,以避免协议对如何解读策略列表做出强制规定。以下是一个简单实现建议:

  • 针对 user(用户)规则…
    • 作用于用户:应将该用户加入订阅者的忽略列表。
    • 作用于房间:应禁止该用户进入该房间(可见时或立即)。
    • 作用于服务器:不应允许该用户向服务器上的其他用户发送邀请。
  • 针对 room(房间)规则…
    • 作用于用户:该用户应离开该房间,并不得重新加入(参见 MSC2270 风格的忽略策略)。
    • 作用于房间:无操作,因为房间无法对自己执行禁令。
    • 作用于服务器:服务器应阻止用户加入该房间,并阻止他们收到该房间的邀请。
  • 针对 server(服务器)规则…
    • 作用于用户:不应让该用户从该服务器接收事件或邀请。
    • 作用于房间:应将该服务器添加到 ACL 的拒绝服务器列表中。
    • 作用于服务器:订阅者应尽量避免与该服务器进行联邦交互,通过阻止来自该服务器的邀请,不发送除非必要的流量(不发送外部邀请)来实现。

订阅策略列表

这一部分有意留作实现细节。对于使用客户端-服务器 API 的实现而言,这只需像加入或窥视房间一样简单。但加入或窥视并非必需:实现可以通过轮询更新或采用其他方式接收策略规则的更新。

事件

状态事件中描述的 entity 采用 glob 风格模式进行解释。注意,针对房间的规则既可以描述房间 ID 也可以描述房间别名——如有需要,由订阅者负责将别名解析为房间 ID。

m.policy.rule.user


A moderation policy rule which affects users.

Event type: State event
State key An arbitrary string decided upon by the sender.

Content

Name Type Description
entity string

Required: The entity affected by this rule. Glob characters * and ? can be used to match zero or more characters or exactly one character respectively.

reason string

Required: The human-readable description for the recommendation.

recommendation string

Required: The suggested action to take. Currently only m.ban is specified.

Examples

{
  "content": {
    "entity": "@alice*:example.org",
    "reason": "undesirable behaviour",
    "recommendation": "m.ban"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "rule:@alice*:example.org",
  "type": "m.policy.rule.user",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.policy.rule.room


A moderation policy rule which affects room IDs and room aliases.

Event type: State event
State key An arbitrary string decided upon by the sender.

Content

Name Type Description
entity string

Required: The entity affected by this rule. Glob characters * and ? can be used to match zero or more characters or exactly one character respectively.

reason string

Required: The human-readable description for the recommendation.

recommendation string

Required: The suggested action to take. Currently only m.ban is specified.

Examples

{
  "content": {
    "entity": "#*:example.org",
    "reason": "undesirable content",
    "recommendation": "m.ban"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "rule:#*:example.org",
  "type": "m.policy.rule.room",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

m.policy.rule.server


A moderation policy rule which affects servers.

Event type: State event
State key An arbitrary string decided upon by the sender.

Content

Name Type Description
entity string

Required: The entity affected by this rule. Glob characters * and ? can be used to match zero or more characters or exactly one character respectively.

reason string

Required: The human-readable description for the recommendation.

recommendation string

Required: The suggested action to take. Currently only m.ban is specified.

Examples

{
  "content": {
    "entity": "*.example.org",
    "reason": "undesirable engagement",
    "recommendation": "m.ban"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "rule:*.example.org",
  "type": "m.policy.rule.server",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

如上所述,客户端行为未做强制定义。

服务器行为

本模块对服务器没有提出额外要求。

安全考虑

本模块可用于构建一套共享黑名单系统,如果部署不当,可能导致现有社区出现分化。对所有社群而言,这未必是合适的解决方案。

具体实现中,依据如何处理订阅关系,用户ID 有可能与策略列表关联进而暴露该用户的立场。例如,若客户端实现让用户加入策略房间,则会向策略房间的观察者显示该用户的 ID。未来,MSC1228MSC1777(或相似手段)可有助于缓解这一问题。

空间

[Added in v1.2]

空间常用于将主题相似的房间进行分组(例如公共的“Official matrix.org rooms”空间或个人的“Work stuff”空间),是一种用于组织房间的方式,同时自身也被表示为房间。

空间通过 m.space 房间类型 定义,因此被称为“空间房间(space-room)”。空间的名称、主题、头像、别名等,均通过空间房间内已有的相关状态事件来定义。

在空间房间内发送普通的 m.room.message 事件是不推荐的——客户端通常并不预期会有方法渲染该房间的时间线。因此,空间房间应当通过设置 m.room.power_levels 中的 events_default 为足够高的数值来禁止普通事件的发布。在默认的权限层级结构中,该值应为 100。客户端还可进一步不对空间房间计入通知数。

空间成员资格通过现有的房间管理机制定义和控制:即 m.room.memberm.room.history_visibilitym.room.join_rules。建议公共空间与公共房间采用类似设置:world_readable 的历史可见性、已发布的规范别名以及适当的公共加入规则。邀请(包括第三方邀请)同样适用于空间房间。

常规房间的其他特性也同样适用于空间,如可设置任意状态事件、存储房间账户数据等。空间本质上是具有额外功能的房间。

管理空间内包含的房间/空间

空间组成了一个房间层级体系,客户端可借此将房间列表结构化为树状视图。父子关系有两种定义方式:在空间房间中通过 m.space.child 状态事件,或在子房间中通过 m.space.parent 状态事件。

多数情况下,应同时定义子房间与父房间的关系,以便于发现空间及其内容。仅使用 m.space.child 时,空间实质上就像一个由空间管理者精心挑选的房间列表,而房间本身可能并不知晓被包含其中。仅使用 m.space.parent 时,房间则会被“秘密”添加到空间中,而不会被空间直接宣传。

鉴于空间本身就是房间,因此可以在空间中嵌套空间,也存在创建环路(循环)的可能。尽管明确禁止创建循环,实际实现时仍可能遇到这种情况,必须注意避免无限循环。

客户端及服务器还需警惕树结构过长,以免带来性能问题。

m.space.child 关系

采用此方法时,状态事件发送至作为父房间的空间房间,事件的 state_key 为子房间的ID。

例如,实现以下结构:

#space:example.org
    #general:example.org (!abcdefg:example.org)
    !private:example.org

#space:example.org 的状态为:

为简明起见,省略无关字段。

{
    "type": "m.space.child",
    "state_key": "!abcdefg:example.org",
    "content": {
        "via": ["example.org"]
    }
}
{
    "type": "m.space.child",
    "state_key": "!private:example.org",
    "content": {
        "via": ["example.org"]
    }
}

子房间本身无需任何状态事件(当然也可以存在)。如此,用户可以无需房间版主/管理员明确授权,定义个人/私有空间组织自己的房间。

通过在相关状态事件的 content 中省略 via 键(如通过撤回或清空 content),可将子房间从空间中移除。

m.space.child


Defines the relationship of a child room to a space-room. Has no effect in rooms which are not spaces.

Event type: State event
State key The child room ID being described.

Content

Name Type Description
order string

Optional string to define ordering among space children. These are lexicographically compared against other children’s order, if present.

Must consist of ASCII characters within the range \x20 (space) and \x7E (~), inclusive. Must not exceed 50 characters.

order values with the wrong type, or otherwise invalid contents, are to be treated as though the order key was not provided.

See Ordering of children within a space for information on how the ordering works.

suggested boolean

Optional (default false) flag to denote whether the child is “suggested” or of interest to members of the space. This is primarily intended as a rendering hint for clients to display the room differently, such as eagerly rendering them in the room list.

via [string]

Required: A list of servers to try and join through. See also: Routing.

When not present or invalid, the child room is not considered to be part of the space.

Examples

{
  "content": {
    "order": "lexicographically_compare_me",
    "suggested": true,
    "via": [
      "example.org",
      "other.example.org"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "!roomid:example.org",
  "type": "m.space.child",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}
空间内子项排序

当客户端展示空间的子项时,应按照以下算法排序。在部分场景(如传统的左侧房间列表),客户端可能会覆盖排序规则以提升用户体验。但理论上的空间摘要视图会显示有序的子项。

对于空间的所有子项,先将带有有效 order 键的子项按照 Unicode 码点字典序排序,使得 \x20(空格)在 \x7E~)之前。再将剩余未定义 order 的子项按其 m.space.child 事件的 origin_server_ts 时间戳升序排列,置于前者之后。

order 值相同,则按事件时间戳排序。若时间戳也相同,则按照房间ID(即 state key)升序字典序排列。

注意此处对 ASCII 空格的精确用法,以下为一组空间子项的合理排序示例:

为简明起见,省略无关字段。

[
    {
        "type": "m.space.child",
        "state_key": "!b:example.org",
        "origin_server_ts": 1640341000000,
        "content": {
            "order": " ",
            "via": ["example.org"]
        }
    },
    {
        "type": "m.space.child",
        "state_key": "!a:example.org",
        "origin_server_ts": 1640141000000,
        "content": {
            "order": "aaaa",
            "via": ["example.org"]
        }
    },
    {
        "type": "m.space.child",
        "state_key": "!c:example.org",
        "origin_server_ts": 1640841000000,
        "content": {
            "order": "first",
            "via": ["example.org"]
        }
    },
    {
        "type": "m.space.child",
        "state_key": "!e:example.org",
        "origin_server_ts": 1640641000000,
        "content": {
            "via": ["example.org"]
        }
    },
    {
        "type": "m.space.child",
        "state_key": "!d:example.org",
        "origin_server_ts": 1640741000000,
        "content": {
            "via": ["example.org"]
        }
    }
]
  1. !b:example.org 排在最前,因为 \x20 字典序在 aaaa 之前。
  2. !a:example.org 紧随其后,因为 aaaa 字典序在 first 之前。
  3. !c:example.org 接下来,因为 first 是最后一个 order 值。
  4. !e:example.org 其后,因为其事件时间戳最小。
  5. !d:example.org 最后,因为其事件时间戳最大。
m.space.parent 关系

房间还可以通过在自身状态中添加父房间事件来声明属于某个空间。类似空间中的子事件,父事件的 state_key 是父空间的房间ID,content 中的 via 列表用于说明链接是否有效,以及可通过哪些服务器加入。

为避免房间伪称属于某空间,m.space.parent 事件在下列任一条件满足时才应被接受:

  • 在设定为父空间的房间中可找到对应的 m.space.child 事件。
  • m.space.parent 事件的发送者在该父空间拥有足够权限可发送 m.space.child 状态事件(无需确有对应子事件存在)。

如客户端尚未加入父空间,可能需要窥探父空间房间状态。若客户端无法窥探,则应认为链接无效。

第二个条件的后果是:若房间管理员在父空间内被降权、退出或被移除父空间,则之前合法的 m.space.parent 事件可能变为无效。

m.space.parent 事件的 content 可包含布尔值 canonical,表示该父空间为该房间的主空间。例如可用于让客户端通过窥探该空间发现其他相关房间并向用户推荐。只能有一个主(canonical)父空间,尽管这一点没有强制约束。若有冲突,采用 Unicode 码点升序排序的最小房间ID进行决议。

m.space.parent


Defines the relationship of a room to a parent space-room.

Event type: State event
State key The parent room ID.

Content

Name Type Description
canonical boolean

Optional (default false) flag to denote this parent is the primary parent for the room.

When multiple canonical parents are found, the lowest parent when ordering by room ID lexicographically by Unicode code-points should be used.

via [string]

Required: A list of servers to try and join through. See also: Routing.

When not present or invalid, the room is not considered to be part of the parent space.

Examples

{
  "content": {
    "canonical": true,
    "via": [
      "example.org",
      "other.example.org"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "!parent_roomid:example.org",
  "type": "m.space.parent",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

在空间中发现房间

客户端常需帮助用户探索某空间包含哪些房间/空间。可通过在客户端中遍历该空间的 m.space.child 状态事件并窥探房间以获取名称等信息,然而这种方式在大多数场景下并不实用。

为此,提供了一个层级API以深度优先方式遍历空间树并发现带美观细节的房间信息。

GET /hierarchy API 按深度优先方式工作:遇到子项为空间时将递归至该空间,然后返回非空间子房间。

循环虽被禁止,但仍有可能出现。服务器应优雅地中断循环。

此外,某个子房间(例如作为孙子房间)可能多次出现在响应中。

GET /_matrix/client/v1/rooms/{roomId}/hierarchy


Added in v1.2

Paginates over the space tree in a depth-first manner to locate child rooms of a given space.

Where a child room is unknown to the local server, federation is used to fill in the details. The servers listed in the via array should be contacted to attempt to fill in missing rooms.

Only m.space.child state events of the room are considered. Invalid child rooms and parent events are not covered by this endpoint.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room ID of the space to get a hierarchy for.

query parameters
Name Type Description
from string

A pagination token from a previous result. If specified, max_depth and suggested_only cannot be changed from the first request.

limit integer

Optional limit for the maximum number of rooms to include per response. Must be an integer greater than zero.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

max_depth integer

Optional limit for how far to go into the space. Must be a non-negative integer.

When reached, no further child rooms will be returned.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.

suggested_only boolean

Optional (default false) flag to indicate whether or not the server should only consider suggested rooms. Suggested rooms are annotated in their m.space.child event contents.


Responses

Status Description
200 A portion of the space tree, starting at the provided room ID.
400

The request was invalid in some way. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The from token is unknown to the server.
  • suggested_only or max_depth changed during pagination.
403

The user cannot view or peek on the room. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The room is not set up for peeking.
  • The user has been banned from the room.
  • The room does not exist.
429 This request was rate-limited.

200 response

Name Type Description
next_batch string

A token to supply to from to keep paginating the responses. Not present when there are no further results.

rooms [SpaceHierarchyRoomsChunk]

Required: The rooms for the current page, with the current filters.

The server should return any rooms where at least one of the following conditions is true:

  • The requesting user is currently a member (their room membership is join).
  • The requesting user already has permission to join, i.e. one of the following:
    • The user’s room membership is invite.
    • The room’s join rules are set to public.
    • The room’s join rules are set to restricted, provided the user meets one of the specified conditions.
  • The room is “knockable” (the room’s join rules are set to knock, or knock_restricted, in a room version that supports those settings).
  • The room’s m.room.history_visibility is set to world_readable.
SpaceHierarchyRoomsChunk
Name Type Description
avatar_url URI

The URL for the room’s avatar, if one is set.

canonical_alias string

The canonical alias of the room, if any.

children_state [StrippedChildStateEvent]

Required: The m.space.child events of the space-room, represented as Stripped State Events with an added origin_server_ts key.

If the room is not a space-room, this should be empty.

guest_can_join boolean

Required: Whether guest users may join the room and participate in it. If they can, they will be subject to ordinary power level rules like any other user.

join_rule string

The room’s join rule. When not present, the room is assumed to be public.

name string

The name of the room, if any.

num_joined_members integer

Required: The number of members joined to the room.

room_id string

Required: The ID of the room.

room_type string

The type of room (from m.room.create), if any.

Added in v1.4

topic string

The topic of the room, if any.

world_readable boolean

Required: Whether the room may be viewed by guest users without joining.

StrippedChildStateEvent
Name Type Description
content EventContent

Required: The content for the event.

origin_server_ts integer

Required: The origin_server_ts for the event.

sender string

Required: The sender for the event.

state_key string

Required: The state_key for the event.

type string

Required: The type for the event.

{
  "next_batch": "next_batch_token",
  "rooms": [
    {
      "avatar_url": "mxc://example.org/abcdef",
      "canonical_alias": "#general:example.org",
      "children_state": [
        {
          "content": {
            "via": [
              "example.org"
            ]
          },
          "origin_server_ts": 1629413349153,
          "sender": "@alice:example.org",
          "state_key": "!a:example.org",
          "type": "m.space.child"
        }
      ],
      "guest_can_join": false,
      "join_rule": "public",
      "name": "The First Space",
      "num_joined_members": 42,
      "room_id": "!space:example.org",
      "room_type": "m.space",
      "topic": "No other spaces were created first, ever",
      "world_readable": true
    }
  ]
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "suggested_only and max_depth cannot change on paginated requests"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not allowed to view this room."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}
服务器行为

当服务器无法获取子房间状态时,可通过联邦接口 GET /hierarchy 请求所需信息。该端点响应应在一段时间内做缓存。响应还可包含请求用户已加入或本地服务器已知的房间信息——本地数据应优先于远端服务器数据。

请注意,返回客户端的响应基于用户上下文。建议服务器对数据做短暂缓存,但仍须进行权限校验以确保响应对于该用户的准确性。

事件替换

[Added in v1.4]

事件替换,或称“消息编辑事件”,是指那些使用 事件关系rel_typem.replace 的事件,表示原始事件将被替换。

一条消息编辑事件的示例如下:

{
    "type": "m.room.message",
    "content": {
        "body": "* Hello! My name is bar",
        "msgtype": "m.text",
        "m.new_content": {
            "body": "Hello! My name is bar",
            "msgtype": "m.text"
        },
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": "$some_event_id"
        }
    },
    // ... 事件所需的其他字段
}

替换事件的 content 必须包含 m.new_content 属性,用于定义替换后的内容。正常的 content 属性(如 bodymsgtype 等)则为不支持替换事件的客户端提供兼容回退。

m.new_content 可以包含事件内容中通常存在的任意属性,例如 formatted_body(参见 m.room.message msgtypes)。

替换事件的有效性

替换事件需满足一系列要求,才能被视为有效替换:

  • 如同所有的事件关系一样,原始事件和替换事件必须具有相同的 room_id(即不能在一个房间发送事件,在另一个房间发送其编辑版本)。
  • 原始事件与替换事件必须拥有相同的 sender(即不能编辑他人的消息)。
  • 替换事件和原始事件的 type 必须相同(即不能更改原始事件的类型)。
  • 替换事件和原始事件不得包含 state_key 属性(即完全不能编辑状态事件)。
  • 原始事件本身不能具有 rel_typem.replace(即不能编辑一条编辑事件——但可以为同一原始事件发送多次编辑)。
  • 替换事件(若适用,解密后)必须包含 m.new_content 属性。

如果未满足上述任一条件,则实现应忽略该替换事件(不应替换原文内容,也不应将该编辑纳入服务端聚合)。

请注意,替换事件 m.room.messagemsgtype 属性不必与原始事件相同。例如,将 m.text 事件替换为 m.emote 是合法的。

编辑加密事件

若原始事件是 加密 的,则替换事件也应加密。在这种情况下,m.new_content 被放置于加密负载的内容中。如同所有事件关系,m.relates_to 属性必须位于事件的未加密(明文)部分。

例如,一个加密事件的替换事件可能如下所示:

{
    "type": "m.room.encrypted",
    "content": {
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": "$some_event_id"
        },
        "algorithm": "m.megolm.v1.aes-sha2",
        "sender_key": "<sender_curve25519_key>",
        "device_id": "<sender_device_id>",
        "session_id": "<outbound_group_session_id>",
        "ciphertext": "<encrypted_payload_base_64>"
    }
    // 未显示无关字段
}

一旦解密,负载内容可能如下:

{
    "type": "m.room.<event_type>",
    "room_id": "!some_room_id",
    "content": {
        "body": "* Hello! My name is bar",
        "msgtype": "m.text",
        "m.new_content": {
            "body": "Hello! My name is bar",
            "msgtype": "m.text"
        }
    }
}

请注意:

  • 加密负载中没有 m.relates_to 属性。如果有,将会被忽略。
  • m.room.encrypted 事件明文内容中没有 m.new_content 属性。如果有,同样会被忽略。

加密替换事件的负载必须如常加密,包括像往常一样推进任何 Megolm 会话。不应重复使用原有的 Megolm ratchet 条目。

应用 m.new_content

应用替换时,原始事件的 content 被视为被 m.new_content 全量覆盖,仅保留 m.relates_to 属性不变m.new_content 内部的任何 m.relates_to 属性均被忽略。

例如,给定以下两条事件:

{
    "event_id": "$original_event",
    "type": "m.room.message",
    "content": {
        "body": "I really like cake",
        "msgtype": "m.text",
        "formatted_body": "I really like cake",
    }
}
{
    "event_id": "$edit_event",
    "type": "m.room.message",
    "content": {
        "body": "* I really like *chocolate* cake",
        "msgtype": "m.text",
        "m.new_content": {
            "body": "I really like *chocolate* cake",
            "msgtype": "m.text",
            "com.example.extension_property": "chocolate"
        },
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": "$original_event_id"
        }
    }
}

……最终结果如下所示:

{
    "event_id": "$original_event",
    "type": "m.room.message",
    "content": {
        "body": "I really like *chocolate* cake",
        "msgtype": "m.text",
        "com.example.extension_property": "chocolate"
    }
}

注意此时 formatted_body 已不存在,因为替换事件中已省略该字段。

服务器行为

服务端对 m.replace 关系的聚合

[Changed in v1.7]

请注意,同一个原始事件可以有多个 m.replace 关系的事件(例如多次编辑)。这些应由主服务器进行 聚合

m.replace 关系的聚合格式会提供最新的替换事件,格式 同常规

最新事件通过比较 origin_server_ts 决定;若有两个或以上替换事件 origin_server_ts 相同,则以字典序最大的 event_id 为最新。

同其他子事件聚合一样,对应于 m.replace 关系的聚合包含在被目标事件的 unsignedm.relations 属性下。例如:

{
  "event_id": "$original_event_id",
  "type": "m.room.message",
  "content": {
    "body": "I really like cake",
    "msgtype": "m.text",
    "formatted_body": "I really like cake"
  },
  "unsigned": {
    "m.relations": {
      "m.replace": {
        "event_id": "$latest_edit_event_id",
        "origin_server_ts": 1649772304313,
        "sender": "@editing_user:localhost"
        "type": "m.room.message",
        "content": {
          "body": "* I really like *chocolate* cake",
          "msgtype": "m.text",
          "m.new_content": {
            "body": "I really like *chocolate* cake",
            "msgtype": "m.text"
          },
          "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": "$original_event_id"
          }
        }
      }
    }
  }
  // 未显示无关字段
}

如果原始事件被 抹除,则任何 m.replace 关系不应与其打包(无论后续替换本身是否被抹除)。请注意,此行为特定于 m.replace 关系。另请参考下文 已编辑事件的抹除

注意:原始事件的 content 保持不变。特别是服务器不应将内容用替换事件内容替换。

此前规范版本要求服务器在向客户端提供已编辑事件时替换其内容(除 GET /_matrix/client/v3/rooms/{roomId}/event/{eventId} 接口外)。然而,这样会导致客户端实现难以保持一致,因此服务器不再进行此操作。

客户端行为

由于服务器不会替换任何已编辑事件内容,客户端应注意所有收到的替换事件,并尽可能和适当时应用替换。

客户端作者请注意 替换事件的有效性 要求,忽略所有无效的替换事件。

永久链接

创建指向事件的链接(即永久链接)时,客户端将构建指向其当前所见事件的链接(可能是消息编辑事件)。

查看该永久链接的客户端应定位到原始事件,并显示该事件的最新版本。

已编辑事件的抹除

当使用 rel_typem.replace 的事件被 抹除 时,该编辑修订被移除。如果有后续编辑,影响较小;但如果这是最新编辑,则事件实际上回退为被抹除编辑前的内容。

抹除原始消息则实际上移除该消息及所有后续编辑,使其不再出现在可见时间线上。在这种情况下,homeserver 会如同处理其他抹除事件一样,为原始事件返回空的 content,且如 前述 替换事件不会打包于原始事件对应的聚合中。注意后续编辑本身并没有被真正抹除:它们仅在可见时间线之外不发挥作用。

带有提及的事件编辑

编辑包含 用户和房间提及 的事件时,替换事件会含有两个 m.mentions 属性:

  • 位于 content 顶层的,记录该修订中产生的新提及。
  • 位于 m.new_content 属性内的,记录事件最新版本中所有已解析的提及。

以上差异可确保用户不会对事件的每次编辑都收到通知,但又允许提及新用户(或在编辑幅度足够大的情况下重新通知)。

例如,存在一条提及 Alice 的事件:

{
    "event_id": "$original_event",
    "type": "m.room.message",
    "content": {
        "body": "Hello Alice!",
        "m.mentions": {
            "user_ids": ["@alice:example.org"]
        }
    }
}

编辑后同时提及 Bob:

{
  "content": {
    "body": "* Hello Alice & Bob!",
    "m.mentions": {
      "user_ids": [
        // 仅包含新提及的用户
        "@bob:example.org"
      ]
    },
    "m.new_content": {
      "body": "Hello Alice & Bob!",
      "m.mentions": {
        "user_ids": [
          // 包含所有已提及的用户
          "@alice:example.org",
          "@bob:example.org"
        ]
      },
    },
    "m.relates_to": {
      "rel_type": "m.replace",
      "event_id": "$original_event"
    }
  },
  // 事件需要的其他字段
}

若某一修订移除了某个用户的提及,则该用户的 Matrix ID 不应出现在任何 m.mentions 属性中。

客户端也可据此调整 提及事件的客户端行为,通过检查 m.new_content 下的 m.mentions 属性判定事件是否提及当前用户。

回复消息的编辑

对替换 回复 的事件存在特殊约束:与原始回复不同,m.relates_to 对象中不得出现 m.in_reply_to 属性,因为这将显得多余(见上文应用 m.new_content 章节已说明原始事件的 m.relates_to 会保留),且与事件关系机制“一事件只存在一个‘父级’”的理念相悖。

[Changed in v1.13] 规范早期版本允许替换 回复 的事件在 content 中包含回退信息。此规则已废除。

编辑回复的示例如下:

{
  "type": "m.room.message",
  // 未显示无关字段
  "content": {
    "body": "* reply",
    "msgtype": "m.text",
    "m.new_content": {
      "body": "reply",
      "msgtype": "m.text",
    },
    "m.relates_to": {
      "rel_type": "m.replace",
      "event_id": "$original_reply_event"
    }
  }
}

事件注释与反应

[Added in v1.7]

m.annotation 关系类型

注释是一类采用event 关系并带有 rel_typem.annotation 的事件。

注释通常用于“反应”:例如,如果用户想要对某个事件表示点赞,则客户端会发送一个带有相应表情(如👍)的注释事件。另一个可能的用例是让机器人发送事件来指示某条命令的成功或失败。

除了标准属性 event_idrel_type 外,m.relates_to 属性中的 rel_type: m.annotation 应包含一个 key,用于表示所应用的注释。例如,在使用表情符号进行反应时,key 包含所使用的表情符号。

如下所示是一个 m.annotation 关系的示例:

"m.relates_to": {
    "rel_type": "m.annotation",
    "event_id": "$some_event_id",
    "key": "👍"
}

任何类型的事件都可以被注释,包括状态事件。

事件

m.reaction


Indicates a reaction to a previous event.

Has no defined content properties of its own. Its only purpose is to hold an m.relates_to property.

Since they contain no content other than m.relates_to, m.reaction events are normally not encrypted, as there would be no benefit in doing so.

Event type: Message event

Content

Name Type Description
m.relates_to ReactionRelatesTo

Indicates the event being reacted to, and the type of reaction.

ReactionRelatesTo
Name Type Description
event_id string

The event ID of the event that this is a reaction to.

key string

The reaction being made, usually an emoji.

If this is an emoji, it should include the unicode emoji presentation selector (\uFE0F) for codepoints which allow it (see the emoji variation sequences list).

rel_type string

One of: [m.annotation].

Examples

{
  "content": {
    "m.relates_to": {
      "event_id": "$some_event_id",
      "key": "👍",
      "rel_type": "m.annotation"
    }
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.reaction",
  "unsigned": {
    "age": 1234,
    "membership": "join"
  }
}

客户端行为

注释设计的意图是对其进行计数,而不是单独展示。客户端必须为每个事件统计他们观察到的给定事件 type 和注释 key 的注释数量;这些计数通常在时间线上与事件一起显示。

在进行计数时:

  • 每个事件 type 和注释 key 通常应分别计数,但是否实际分开计数取决于具体的实现。

  • 被忽略用户发送的注释事件应排除在计数之外。

  • 来自同一用户(即 sender 相同)的多个完全相同的注释(即 typekey 都相同)应计为一次注释。

  • 对于引用了自身带有 m.relates_to,其 rel_typem.annotationrel_typem.replace 的事件的注释事件,实现应忽略。换句话说,替换事件或注释本身不能被再次注释。注释应仅指向原始事件。

  • 当某个注释被撤回时,应从计数中移除。

反应不可编辑,因为替换事件不会更改 m.relates_to(见应用 m.new_content),并且 m.reaction 中没有其他有意义的内容。如果用户希望更改自己的反应,应该撤回原始反应,并发送新的反应事件替代。

m.reaction 中的 key 字段可以为任意字符串,因此客户端在渲染过长反应内容时需采取合理方式。例如,客户端可以省略过长的反应内容。

服务器行为

避免重复注释

HomeServer 应当防止用户针对同一事件,使用相同的事件 type 和注释 key 发送第二次注释(除非第一次发送的事件已被撤回)。

试图发送此类注释应返回 400 错误以及错误码 M_DUPLICATE_ANNOTATION

但这并不能保证重复的注释不会通过联邦网络到达。客户端在计数注释时有责任对接收到的注释进行去重。

服务器端对 m.annotation 关系的聚合

m.annotation 关系不会被服务器聚合。换句话说,m.annotation 不会包含在 m.relations 属性中。

线程

[Added in v1.4]

线程允许用户在一个房间中以可视方式分支他们的对话。通常在线上讨论多个主题时使用,线程相较于传统的 富回复 能够提供更有组织的交流方式,而富回复未必能够兼顾所有场景。

客户端应当在时间线上以区别于普通消息或回复的方式渲染线程,例如为线程提供一些上下文信息,但将完整的对话历史隐藏于可展开内容之后。

线程通过 rel_type 设为 m.thread 来建立,并引用 线程根(即该线程事件所指向的主时间线事件)。无法从本身已是事件关系子事件(即带有 m.relates_torel_type 属性的事件,参考 关系类型)创建线程。因此,线程也无法嵌套。

与富回复链不同,线程中的所有事件都引用线程根,而不是最新的消息。

下面通过示例展示线程及其形成方式:

{
  // 已省略无关字段
  "type": "m.room.message",
  "event_id": "$alice_hello",
  "sender": "@alice:example.org",
  "content": {
    "msgtype": "m.text",
    "body": "Hello world! How are you?"
  }
}
{
  // 已省略无关字段
  "type": "m.room.message",
  "event_id": "$bob_hello",
  "sender": "@bob:example.org",
  "content": {
    "m.relates_to": {
      "rel_type": "m.thread",
      "event_id": "$alice_hello"
    },
    "msgtype": "m.text",
    "body": "I'm doing okay, thank you! How about yourself?"
  }
}
{
  // 已省略无关字段
  "type": "m.room.message",
  "event_id": "$alice_reply",
  "sender": "@alice:example.org",
  "content": {
    "m.relates_to": {
      "rel_type": "m.thread",
      "event_id": "$alice_hello" // 注意:始终指向 *线程根*
    },
    "msgtype": "m.text",
    "body": "I'm doing great! Thanks for asking."
  }
}

如上所示,任何没有 rel_type 的事件都可以仅通过 m.thread 关系被引用来成为线程根。

非线程化客户端的回退机制

能够理解线程的客户端应直接以线程方式处理,但某些客户端(出于历史原因或功能范围限制)可能无法向用户有效展现对话历史。

为此,支持线程的客户端发送事件时应包含 富回复 元数据,以尝试形成对话的回复链。这种方式在高线程活跃房间中并不理想,但可以为用户提供与房间内其他消息相关的上下文信息。

该兼容方式通过合并两种关系并为 is_falling_back 标记设为 true 实现。

// 在事件内容中……
"m.relates_to": {
  // m.thread 关系结构
  "rel_type": "m.thread",
  "event_id": "$root",

  // 富回复结构
  "m.in_reply_to": {
    // 线程中客户端已知的最新消息,应选取其他客户端有较大渲染概率的事件,
    // 如 `m.room.message` 事件。
    "event_id": "$target"
  },

  // 标记此事件为带回复回退的线程
  "is_falling_back": true
}

对于对线程有一定感知(即不直接渲染线程、但知道规范中有该功能)的客户端,可以将对带有 rel_typem.thread 事件的富回复视作线程内部的回复,以实现线程客户端侧的对话连续性。

实现方法为:从被回复事件中复制出 event_id(线程根),添加 m.in_reply_to 元数据,并在 m.relates_to 中加入 is_falling_back: true

线程内的回复

非线程化客户端的回退机制 部分,为 m.relates_to 新增了 is_falling_back 字段。当未提供该字段时,默认为 false,这同样允许线程消息本身作为回复。

除了 is_falling_backfalse(或未指定)以外,客户端应利用非线程化客户端的回退机制在线程内创建回复,并据此渲染事件。

服务器行为

m.thread 关系的验证

服务器应拒绝客户端针对带有 m.relates_to 属性的事件尝试发起线程的请求。如果客户端试图对带有 m.relates_to 属性的事件作为目标事件,则应返回 HTTP 400 错误及相应错误信息,按照 标准错误响应 结构处理。

此种情况目前没有单独的错误码:服务器应与 HTTP 400 一同返回 M_UNKNOWN

服务器侧对 m.thread 关系的聚合

由于线程总是引用线程根,一个事件将拥有多个“子事件”,共同组成该线程。服务器应对这些事件进行 聚合

线程聚合的数据包括用户在该线程中的参与情况、线程(服务器已知范围内)大致的事件数量,以及线程内最新(按服务器视角的拓扑顺序)的一条消息。

与任何其他子事件聚合一样,m.thread 聚合结果通过 unsigned 下的 m.relations 属性返回给线程根。例如:

{
  "event_id": "$root_event",
  // 未显示无关字段
  "unsigned": {
    "m.relations": {
      "m.thread": {
        "latest_event": {
          // 线程中最新事件的序列化副本。
          // 部分字段为简化未示出。
          "event_id": "$message",
          "sender": "@alice:example.org",
          "room_id": "!room:example.org",
          "type": "m.room.message",
          "content": {
            "msgtype": "m.text",
            "body": "Woo! Threads!"
          },
          "unsigned": {
            "m.relations": {
              // ...
            }
          }
        },
        "count": 7,
        "current_user_participated": true
      }
    }
  }
}

latest_event 为线程中由未被忽略的用户发送,服务器视拓扑顺序最新的一条事件。

注意,正如上例,latest_event 的子事件本身也需被聚合并包含在该事件下的 m.relations 下。服务器需注意避免形成循环,尽管由于 m.thread 不允许指向带有 m.relates_to 属性的事件,目前不可能产生循环。

count 仅指向目标事件的 rel_typem.thread 的事件数量,未包含被忽略用户发送的事件。

current_user_participatedtrue 时,表明认证用户满足以下任一条件:

  1. 是线程根事件的 sender
  2. 是某个引用线程根且 rel_typem.thread 的事件的 sender

查询房间内线程

客户端如需获取某线程内的所有事件,可通过 GET /relations/{threadRootId}/m.thread; 如需获取某房间内所有线程,则需专用 API:

GET /_matrix/client/v1/rooms/{roomId}/threads


Added in v1.4

This API is used to paginate through the list of the thread roots in a given room.

Optionally, the returned list may be filtered according to whether the requesting user has participated in the thread.

Rate-limited: Yes
Requires authentication: Yes

Request

Request parameters

path parameters
Name Type Description
roomId string

Required: The room ID where the thread roots are located.

query parameters
Name Type Description
from string

A pagination token from a previous result. When not provided, the server starts paginating from the most recent event visible to the user (as per history visibility rules; topologically).

include string

Optional (default all) flag to denote which thread roots are of interest to the caller. When all, all thread roots found in the room are returned. When participated, only thread roots for threads the user has participated in will be returned.

One of: [all, participated].

limit integer

Optional limit for the maximum number of thread roots to include per response. Must be an integer greater than zero.

Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.


Responses

Status Description
200 A portion of the available thread roots in the room, based on the filter criteria.
400

The request was invalid in some way. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The from token is unknown to the server.
403

The user cannot view or peek on the room. A meaningful errcode and description error text will be returned. Example reasons for rejection are:

  • The room is not set up for peeking.
  • The user has been banned from the room.
  • The room does not exist.
429 This request was rate-limited.

200 response

Name Type Description
chunk [ClientEvent]

Required: The thread roots, ordered by the latest_event in each event’s aggregated children. All events returned include bundled aggregations.

If the thread root event was sent by an ignored user, the event is returned redacted to the caller. This is to simulate the same behaviour of a client doing aggregation locally on the thread.

next_batch string

A token to supply to from to keep paginating the responses. Not present when there are no further results.

ClientEvent
Name Type Description
content object

Required: The body of this event, as created by the client which sent it.

event_id string

Required: The globally unique identifier for this event.

origin_server_ts integer

Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent.

room_id string

Required: The ID of the room associated with this event.

sender string

Required: Contains the fully-qualified ID of the user who sent this event.

state_key string

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

Required: The type of the event.

unsigned UnsignedData

Contains optional extra information about the event.

UnsignedData
Name Type Description
age integer

The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.

membership string

The room membership of the user making the request, at the time of the event.

This property is the value of the membership property of the requesting user’s m.room.member state at the point of the event, including any changes caused by the event. If the user had yet to join the room at the time of the event (i.e, they have no m.room.member state), this property is set to leave.

Homeservers SHOULD populate this property wherever practical, but they MAY omit it if necessary (for example, if calculating the value is expensive, servers might choose to only implement it in encrypted rooms). The property is not normally populated in events pushed to application services via the application service transaction API (where there is no clear definition of “requesting user”).

Added in v1.11

prev_content EventContent

The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content.

Changed in v1.2: Previously, this field was specified at the top level of returned events rather than in unsigned (with the exception of the GET .../notifications endpoint), though in practice no known server implementations honoured this.

redacted_because ClientEvent

The event that redacted this event, if any.

transaction_id string

The client-supplied transaction ID, for example, provided via PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}, if the client being given the event is the same one which sent it.

{
  "chunk": [
    {
      "content": {
        "body": "This is an example text message",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>This is an example text message</b>",
        "msgtype": "m.text"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234,
        "membership": "join"
      }
    }
  ],
  "next_batch": "next_batch_token"
}

400 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_INVALID_PARAM",
  "error": "Unknown pagination token"
}

403 response

Error
Name Type Description
errcode string

Required: An error code.

error string

A human-readable error message.

{
  "errcode": "M_FORBIDDEN",
  "error": "You are not allowed to view this room."
}

429 response

RateLimitError
Name Type Description
errcode string

Required: The M_LIMIT_EXCEEDED error code

error string

A human-readable error message.

retry_after_ms integer

The amount of time in milliseconds the client should wait before trying the request again.

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

引用关系

[Added in v1.5]

以通用方式引用其他事件时,可以使用 rel_typem.reference 作为一种关系类型。引用本身没有特定含义,通常依赖于具体的应用场景。例如,密钥验证框架便使用引用关系,将不同的事件与某次特定的验证尝试关联起来。

希望支持话题或回复功能的客户端应使用除引用以外的其他关系类型。引用通常用于关联数据而非消息。

服务器行为

m.reference 的服务端聚合

m.reference 关系的聚合格式包含一个名为 chunk 的属性,该属性列出了所有对该事件(父事件)进行 m.reference 的事件。目前,chunk 中的事件只包含单一的 event_id 字段。

例如,给定一个带有如下 m.reference 关系的事件:

{
  "content": {
    "m.relates_to": {
      "rel_type": "m.reference",
      "event_id": "$another_event"
    }
    // 其他需要的内容字段
  }
  // 事件所需的其他字段
}

其聚合结果如下所示:

{
  "m.reference": {
    "chunk": [
      { "event_id": "$one" },
      { "event_id": "$two" }
    ]
  }
}