应用服务 API
Matrix 客户端-服务器 API 与服务器-服务器 API 提供了实现一致的、自包含的去中心化消息结构的手段。然而,它们在实现 Matrix 中自定义服务器端行为(例如网关、过滤器、可扩展钩子等)方面手段有限。应用服务 API (AS API) 定义了一套标准 API,不受底层主服务器实现的影响,以便实现这些可扩展功能。
应用服务
应用服务为被动组件,只能观察来自主服务器的事件。它们可以向参与的房间注入事件,但无法阻止事件的发送,也不能修改事件内容。为了观察来自主服务器的事件,主服务器需要配置,将某些类型的流量传递给应用服务。要实现这一点,需要手动在主服务器配置中加入应用服务的相关信息。
注册
此前,应用服务曾可通过 HTTP API 注册到主服务器。这一机制因安全风险被移除。被攻陷的应用服务可重新注册全局 * 正则,从而窃取主服务器上所有流量。为防止此类风险,现在应用服务必须通过配置文件进行注册,并将这些配置文件与主服务器的配置文件关联。添加配置文件后,主服务器管理员可对注册过程中的可疑正则表达式做合理性检查。
应用服务注册一组用户 ID、房间别名和房间 ID 的“命名空间”。如果某事件与任何命名空间匹配,则称该应用服务对该事件“感兴趣”。
应用服务还可以声明是否应由其独占管理指定命名空间,这称为“独占”命名空间。独占命名空间会阻止用户及其它应用服务在该命名空间内创建或删除实体。通常,当房间映射到另一个服务的真实房间(如 IRC)时,会使用独占命名空间;当应用服务仅对房间本身提供增强功能(如记录或搜索功能)时,可使用非独占命名空间。
注册信息以一组键值对表示,通常编码为 YAML 文件中的对象。其结构如下:
Registration
Registration
| Name | Type | Description |
|---|---|---|
as_token |
string |
Required: A secret token that the application service will use to authenticate requests to the homeserver. |
hs_token |
string |
Required: A secret token that the homeserver will use authenticate requests to the application service. |
id |
string |
Required: A unique, user-defined ID of the application service which will never change. |
namespaces |
Namespaces |
Required: The namespaces that the application service is interested in. |
protocols |
[string] |
The external protocols which the application service provides (e.g. IRC). |
rate_limited |
boolean |
Whether requests from masqueraded users are rate-limited. The sender is excluded. |
receive_ephemeral |
boolean |
Whether the application service wants to receive ephemeral data. Defaults to Added in |
sender_localpart |
string |
Required: The localpart of the user associated with the application service. Events will be sent to the AS if this user is the target of the event, or is a joined member of the room where the event occurred. |
url |
string |
Required: The URL for the application service. May include a path after the domain name. Optionally set to null if no traffic is required. |
| Name | Type | Description |
|---|---|---|
aliases |
[Namespace] |
A list of namespaces defining the room aliases that the application service is interested in. All events sent in a room with an alias which matches one of the namespaces will be sent to the AS. |
rooms |
[Namespace] |
A list of namespaces defining the room IDs that the application service is interested in. All events sent in a room with an ID which matches one of the namespaces will be sent to the AS. |
users |
[Namespace] |
A list of namespaces defining the user IDs that the application
service is interested in, in addition to its |
| Name | Type | Description |
|---|---|---|
exclusive |
boolean |
Required: A true or false value stating whether this application service has exclusive access to events within this namespace. |
regex |
string |
Required: A POSIX regular expression defining which values this namespace includes. |
独占的用户和别名命名空间应在符号后以下划线开头,以避免与主服务器的其他用户发生冲突。应用服务还应尽量在保留命名空间中体现其所代表的具体服务。例如,@_irc_.* 适合作为处理 IRC 的应用服务注册命名空间。
以下是用于 IRC 桥接应用服务的注册文件示例:
id: "IRC Bridge"
url: "http://127.0.0.1:1234"
as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46"
hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"
sender_localpart: "_irc_bot" # 最终为 @_irc_bot:example.org
namespaces:
users:
- exclusive: true
regex: "@_irc_bridge_.*"
aliases:
- exclusive: false
regex: "#_irc_bridge_.*"
rooms: []
针对 users 命名空间,应用服务只能对本地用户注册感兴趣(即,用户 ID 以本地主服务器的 server_name 结尾)。影响其他主服务器用户的事件不会发送给应用服务,即便这些用户恰好匹配 users 命名空间(当然,除非事件影响的房间本身就属于应用服务感兴趣范围,例如该房间中还有另一个应用服务关心的用户)。
对于 rooms 和 aliases 命名空间,所有匹配房间中的事件都会被发送给应用服务。
如果某主服务器上存在多个应用服务,则每个应用服务的 as_token 和 id 必须唯一,这些项用于标识不同应用服务。主服务器必须强制执行此要求。
主服务器 -> 应用服务 API
授权
[Changed in v1.4]
主服务器在向应用服务发出请求时,必须包含 Authorization 头,内容为注册文件中的 hs_token。应用服务必须校验所提供的 Bearer 令牌与其已知的 hs_token 是否匹配,若不匹配则以 M_FORBIDDEN 错误拒绝请求。
Authorization 头的格式类似于 客户端-服务器 API:
Bearer TheHSTokenGoesHere.
在本规范的早期版本中,曾使用 access_token 查询参数。服务器仅在兼容旧版本规范时需发送此查询参数。
如需发送 query_string,建议与 Authorization 头一同发送,以获得最大兼容性。
若两者均提供,应用服务应校验其值是否一致。
旧路由
早期规格的应用服务 API 混合定义了多种在实际部署中被采用的端点。当前应用服务规范对所有端点定义了版本,以便与 Matrix 其他规范及未来更好兼容。
主服务器在与应用服务通信时应优先尝试当前规范指定的端点,但若应用服务返回非成功的 HTTP 状态码(如 404、500、501 等),则主服务器应回退到旧端点。
旧端点和当前端点拥有完全相同的请求体和响应格式,只是路径不同。各端点的对应关系如下:
/_matrix/app/v1/transactions/{txnId}回退到/transactions/{txnId}/_matrix/app/v1/users/{userId}回退到/users/{userId}/_matrix/app/v1/rooms/{roomAlias}回退到/rooms/{roomAlias}/_matrix/app/v1/thirdparty/protocol/{protocol}回退到/_matrix/app/unstable/thirdparty/protocol/{protocol}/_matrix/app/v1/thirdparty/user/{user}回退到/_matrix/app/unstable/thirdparty/user/{user}/_matrix/app/v1/thirdparty/location/{location}回退到/_matrix/app/unstable/thirdparty/location/{location}/_matrix/app/v1/thirdparty/user回退到/_matrix/app/unstable/thirdparty/user/_matrix/app/v1/thirdparty/location回退到/_matrix/app/unstable/thirdparty/location
主服务器应定期重试新版端点,因为应用服务可能已经升级。
未知路由
如果收到对不受支持(或未知)端点的请求,服务器必须响应 404 M_UNRECOGNIZED 错误。
同样,对于已知端点但不支持的 HTTP 方法,应使用 405 M_UNRECOGNIZED 错误指示。
推送事件
应用服务 API 提供事务接口以发送事件列表。每批事件都包含事务 ID,其运行机制如下:
正常情况
HS ---> AS : 主服务器以事务 ID T 发送事件。
<--- : 应用服务返回 200 OK。
AS ACK 丢失
HS ---> AS : 主服务器以事务 ID T 发送事件。
<-/- : AS 200 OK 丢失。
HS ---> AS : 主服务器以相同事务 ID T 重试。
<--- : 应用服务返回 200 OK。若 AS 已处理过这些事件,可对请求 NO-OP(它可通过事务 ID 判断事件是否相同)。
发送给应用服务的事件应为线性处理(仿佛来自事件流)。主服务器必须维护一个待发送给应用服务的事务队列。如果无法连接到应用服务,主服务器应指数退避,直至应用服务恢复可达。由于应用服务无法修改这些事件,主服务器可异步处理这些请求,不阻塞其它功能。主服务器在重试同一事务 ID 时不得修改(如增加额外)要发送的事件,因为应用服务可能已经处理过这些事件。
PUT
/_matrix/app/v1/transactions/{txnId}
This API is called by the homeserver when it wants to push an event (or batch of events) to the application service.
Note that the application service should distinguish state events
from message events via the presence of a state_key, rather than
via the event type.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
txnId |
string |
Required: The transaction ID for this set of events. Homeservers generate these IDs and they are used to ensure idempotency of requests. |
Request body
| Name | Type | Description |
|---|---|---|
ephemeral |
[Event] |
A list of ephemeral data, if the There are only three event types that can currently occur in this list: This property can be omitted if it would be empty. Added in |
events |
[ClientEvent] |
Required: A list of events, formatted as per the Client-Server API. |
| 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’ |
| 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 |
type |
string |
Required: The type of the event. |
unsigned |
UnsignedData |
Contains optional extra information about the event. |
| 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 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 |
prev_content |
EventContent |
The previous Changed in |
redacted_because |
ClientEvent |
The event that redacted this event, if any. |
transaction_id |
string |
The client-supplied transaction ID, for example, provided via
|
Request body example
{
"ephemeral": [
{
"content": {
"$1435641916114394fHBLK:matrix.org": {
"m.read": {
"@erikj:jki.re": {
"ts": 1436451550453
}
},
"m.read.private": {
"@self:example.org": {
"ts": 1661384801651
}
}
}
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.receipt"
},
{
"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"
}
],
"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"
}
}
]
}
Responses
| Status | Description |
|---|---|
200 |
The transaction was processed successfully. |
200 response
{}
推送临时数据
[Added in v1.13]
若在注册文件中启用了 receive_ephemeral 设置,主服务器必须通过事务 API,通过请求体的 ephemeral 属性向应用服务发送与其相关的临时数据。此属性为数组,实际为客户端-服务器 /sync API 的 presence 和 ephemeral 部分的组合。
当前共可向应用服务传递三种事件类型:
m.presence:如上下文要求,必须发送。例如,为与应用服务共享房间的用户,或匹配应用服务命名空间的用户发生的状态更新。m.typing:应用与普通事件相同的规则,必须发送。即应用服务需注册房间本身或对房间内某用户感兴趣。数据格式应与客户端-服务器 API 相同,但需在顶层增加room_id字段,指明事件所属房间。m.receipt:应用与普通事件相同的规则,必须发送。数据格式与客户端-服务器 API 相同,并需在顶层增加room_id字段。针对私有已读回执,只需针对匹配应用服务命名空间的用户发送。普通已读回执和线程已读回执则总会发送。
心跳机制
[Added in v1.7]
应用服务 API 包含心跳(ping)机制,以便应用服务确保主服务器能访问自身。应用服务可利用此机制检测错误配置并适当报告。
实现时应注意,遇到临时性故障(如应用服务先于主服务器启动)不应导致完全失效,而应平滑处理。
机制如下(为简洁省略了可读性错误信息):
正常情况
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
HS <--- AS : 200 OK {}
AS <--- HS : 200 OK {"duration_ms": 123}
hs_token 错误
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
HS <--- AS : 403 Forbidden {"errcode": "M_FORBIDDEN"}
AS <--- HS : 502 Bad Gateway {"errcode": "M_BAD_STATUS", "status": 403, "body": "{\"errcode\": \"M_FORBIDDEN\"}"}
无法连接至应用服务
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
HS -/-> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
AS <--- HS : 502 Bad Gateway {"errcode": "M_CONNECTION_FAILED"}
/_matrix/app/v1/ping 端点如上说明,/_matrix/client/v1/appservice/{appserviceId}/ping 端点见下文客户端-服务器 API 扩展部分。
POST
/_matrix/app/v1/ping
Added in v1.7
This API is called by the homeserver to ensure that the connection works
and the hs_token the homeserver has is correct.
Currently this is only called by the homeserver as a direct result of
the application service calling
POST /_matrix/client/v1/appservice/{appserviceId}/ping.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request body
| Name | Type | Description |
|---|---|---|
transaction_id |
string |
A transaction ID for the ping, copied directly from the
|
Request body example
{
"transaction_id": "mautrix-go_1683636478256400935_123"
}
Responses
| Status | Description |
|---|---|
200 |
The provided hs_token is valid and the ping request was successful. |
200 response
{}
查询
应用服务 API 包含两个查询 API:房间别名与用户 ID。应用服务应在处理查询请求时自行创建所查询的实体。如果应用服务愿意,可主动创建实体。在此过程中,主服务器会阻塞直至实体被创建并配置完成。若主服务器未收到该请求的响应,应重试数次,最终超时。这样,发起请求的客户端会收到 HTTP 408 “请求超时”。
阻塞主服务器,并让应用服务通过客户端-服务器 API 创建实体,比返回 initial sync 风格的 JSON 数据让主服务器初始化房间/用户更简单灵活。同时,也无需建立“回传通道”通知应用服务有关实体的信息,如房间 ID 到别名的映射。
GET
/_matrix/app/v1/users/{userId}
This endpoint is invoked by the homeserver on an application service to query
the existence of a given user ID. The homeserver will only query user IDs
inside the application service’s users namespace. The homeserver will
send this request when it receives an event for an unknown user ID in
the application service’s namespace, such as a room invite.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
userId |
string |
Required: The user ID being queried. |
Responses
| Status | Description |
|---|---|
200 |
The application service indicates that this user exists. The application service MUST create the user using the client-server API. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
The application service indicates that this user does not exist. Optional error information can be included in the body of this response. |
200 response
{}
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
GET
/_matrix/app/v1/rooms/{roomAlias}
This endpoint is invoked by the homeserver on an application service to query
the existence of a given room alias. The homeserver will only query room
aliases inside the application service’s aliases namespace. The
homeserver will send this request when it receives a request to join a
room alias within the application service’s namespace.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
roomAlias |
string |
Required: The room alias being queried. |
Responses
| Status | Description |
|---|---|
200 |
The application service indicates that this room alias exists. The application service MUST have created a room and associated it with the queried room alias using the client-server API. Additional information about the room such as its name and topic can be set before responding. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
The application service indicates that this room alias does not exist. Optional error information can be included in the body of this response. |
200 response
{}
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
第三方网络
应用服务可通过向主服务器注册时的配置声明所支持的协议。这些网络通常为应用服务管理的第三方服务(如 IRC)。应用服务可为其注册协议填充 Matrix 房间目录,如客户端-服务器 API 扩展部分定义。
每种协议可包括若干“位置”(Location,亦称“第三方位置”或 “3PL”)。协议中的“位置”通常是第三方网络中的某处,如 IRC 频道。第三方网络上的用户也可由应用服务表示。
位置和用户可根据应用服务定义的字段检索,如显示名或其他属性。当客户端请求主服务器在特定“网络”(协议)中搜索时,搜索字段会被传递给应用服务进行筛选。
GET
/_matrix/app/v1/thirdparty/location
Retrieve an array of third-party network locations from a Matrix room alias.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
alias |
string |
The Matrix room alias to look up. |
Responses
| Status | Description |
|---|---|
200 |
All found third-party locations. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
No mappings were found with the given parameters. |
200 response
Array of 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"
}
]
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
GET
/_matrix/app/v1/thirdparty/location/{protocol}
Retrieve a list of Matrix portal rooms that lead to the matched third-party location.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
protocol |
string |
Required: The protocol ID. |
| Name | Type | Description |
|---|---|---|
fields |
{string: string} |
One or more custom fields that are passed to the application service to help identify the third-party location. |
Responses
| Status | Description |
|---|---|
200 |
At least one portal room was found. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
No mappings were found with the given parameters. |
200 response
Array of 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"
}
]
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
GET
/_matrix/app/v1/thirdparty/protocol/{protocol}
This API is called by the homeserver when it wants to present clients with specific information about the various third-party networks that an application service supports.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
protocol |
string |
Required: The protocol ID. |
Responses
| Status | Description |
|---|---|
200 |
The protocol was found and metadata returned. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
No protocol was found with the given path. |
200 response
| Name | Type | Description |
|---|---|---|
field_types |
{string: Field Type} |
Required: The type definitions for the fields defined in 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. |
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. |
| 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. |
| Name | Type | Description |
|---|---|---|
desc |
string |
Required: A human-readable description for the protocol, such as the name. |
fields |
object |
Required: Preset values for |
icon |
string |
An optional content URI representing the protocol. Overrides the one provided at the higher level Protocol object. |
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",
"network_id": "freenode"
}
],
"location_fields": [
"network",
"channel"
],
"user_fields": [
"network",
"nickname"
]
}
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
GET
/_matrix/app/v1/thirdparty/user
Retrieve an array of third-party users from a Matrix User ID.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
userid |
string |
The Matrix User ID to look up. |
Responses
| Status | Description |
|---|---|
200 |
An array of third-party users. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
No mappings were found with the given parameters. |
200 response
Array of 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"
}
]
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
GET
/_matrix/app/v1/thirdparty/user/{protocol}
This API is called by the homeserver in order to retrieve a Matrix User ID linked to a user on the third-party network, given a set of user parameters.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
protocol |
string |
Required: The protocol ID. |
| Name | Type | Description |
|---|---|---|
fields |
{string: string} |
One or more custom fields that are passed to the application service to help identify the user. |
Responses
| Status | Description |
|---|---|
200 |
The Matrix User IDs found with the given parameters. |
401 |
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response. |
403 |
The credentials supplied by the homeserver were rejected. |
404 |
No users were found with the given parameters. |
200 response
Array of 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"
}
]
401 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
404 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
客户端-服务器 API 扩展
应用服务可通过向主服务器表明自身身份,使用更强大的客户端-服务器 API 版本。
本节定义的端点主服务器必须在客户端-服务器 API 中仅向应用服务开放。
身份声明
客户端-服务器 API 通过每个请求中的 access_token 推断用户 ID。为避免应用服务需为每个用户维护 access_token,应用服务应同时以其 as_token 作为 access_token,并声明希望以哪一用户(属于应用服务命名空间的用户)伪装身份访问。
输入项:
- 应用服务令牌(
as_token) - 要模拟的应用服务命名空间内的用户 ID
注意事项:
- 适用客户端-服务器 API 的所有方面,除帐户管理。
- 把
as_token赋值给access_token,即通常客户端令牌所在的位置,如查询参数或Authorization头。这有助于应用服务复用客户端 SDK。 - 推荐通过
Authorization头提供access_token,避免其出现在 HTTP 请求日志中。
应用服务可通过在请求 URL 中追加 user_id 查询字符串参数,指定虚拟用户。该 user_id 必须在应用服务的 user 命名空间范围内。若缺省,则主服务器假定应用服务希望以注册文件中 sender_localpart 所指定用户的身份操作。
请求示例:
GET /_matrix/client/v3/account/whoami?user_id=@_irc_user:example.org
Authorization: Bearer YourApplicationServiceTokenHere
时间戳调整
[Added in v1.3]
应用服务可以修改事件关联的时间戳,从而更准确地反映事件的“真实”发送时间。这不会影响事件在服务器端的顺序,但能更好地反映(如桥接服务因对方网络有延迟而希望为消息打上原始时间)的实际时间。
以应用服务身份认证请求时,可追加 ts 查询参数以变更结果事件的 origin_server_ts。如时间戳不被 origin_server_ts 接受,服务器应以错误请求拒绝。
如未指定,则服务器行为不变:以服务器本地系统时间打时间戳,视为“当前”。
ts 查询参数仅以下端点有效:
其它端点(如 /kick)不支持 ts,如需类似行为请用 PUT /state 端点模拟。
变更事件时间不会改变事件在服务器端(DAG)顺序。事件仍会像以“当前时间”发送那样添加到 DAG 顶端。未来的 MSC,如 MSC2716,预计会提供更彻底的 DAG 顺序操作功能(如历史导入等)。
服务器管理员级权限
主服务器需赋予应用服务对其命名空间内所有用户和房间别名“完全控制”权限。这意味着应用服务应能管理命名空间内任意用户和房间别名。无需对房间别名控制权作额外 API 更改。
创建用户需要对 API 作如下调整:
- 绕过验证码。
- 支持“无密码”用户。
为此需完全绕过注册流程。方法是在 /register 请求中附带 as_token,以及登录类型 m.login.application_service,从而指定无需密码的目标用户 ID。
POST /_matrix/client/v3/register
Authorization: Bearer YourApplicationServiceTokenHere
内容:
{
type: "m.login.application_service",
username: "_irc_example"
}
同样,应用服务以用户身份登录,也要允许在无需该用户密码的情况下完成。具体方法是在 /login 请求中附带 as_token,并指定登录类型 m.login.application_service:
[Added in v1.2]
POST /_matrix/client/v3/login
Authorization: Bearer YourApplicationServiceTokenHere
内容:
{
type: "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "_irc_example"
}
}
应用服务如试图超出其定义命名空间创建用户或别名,或以超出命名空间的用户登录,将会收到 M_EXCLUSIVE 错误码。
同理,普通用户试图在应用服务定义的命名空间内创建用户或别名(且该命名空间为独占)同样会收到 M_EXCLUSIVE 错误码。
若带 m.login.application_service 登录类型的 /register 或 /login 请求未附带有效 as_token,将返回 M_MISSING_TOKEN 或 M_UNKNOWN_TOKEN 错误码,HTTP 状态码为 401。其行为与客户端-服务器 API 的无效认证相同(参见使用访问令牌)。
心跳
[Added in v1.7]
这是心跳机制的客户端-服务器 API 对应端点。
POST
/_matrix/client/v1/appservice/{appserviceId}/ping
Added in v1.7
This API asks the homeserver to call the
/_matrix/app/v1/ping endpoint on the
application service to ensure that the homeserver can communicate
with the application service.
This API requires the use of an application service access token (as_token)
instead of a typical client’s access token. This API cannot be invoked by
users who are not identified as application services. Additionally, the
appservice ID in the path must be the same as the appservice whose as_token
is being used.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
appserviceId |
string |
Required: The appservice ID of the appservice to ping. This must be the same
as the appservice whose |
Request body
| Name | Type | Description |
|---|---|---|
transaction_id |
string |
An optional transaction ID that is passed through to the |
Request body example
{
"transaction_id": "mautrix-go_1683636478256400935_123"
}
Responses
| Status | Description |
|---|---|
200 |
The ping was successful. |
400 |
The application service doesn’t have a URL configured. The errcode is M_URL_NOT_SET. |
403 |
The access token used to authenticate the request doesn’t belong to an appservice, or belongs to a different appservice than the one in the path. The errcode is M_FORBIDDEN. |
502 |
The application service returned a bad status, or the connection failed.
The errcode is For bad statuses, the response may include |
504 |
The connection to the application service timed out. The errcode is M_CONNECTION_TIMEOUT. |
200 response
| Name | Type | Description |
|---|---|---|
duration_ms |
integer |
Required: The duration in milliseconds that the
|
{
"duration_ms": 123
}
400 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "M_URL_NOT_SET",
"error": "Application service doesn't have a URL configured"
}
403 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "M_FORBIDDEN",
"error": "Provided access token is not the appservice's as_token"
}
502 response
| Name | Type | Description |
|---|---|---|
body |
string |
The HTTP response body returned by the appservice. |
errcode |
string |
Required: An error code. One of: |
error |
string |
A human-readable error message. |
status |
integer |
The HTTP status code returned by the appservice. |
{
"body": "{\"errcode\": \"M_UNKNOWN_TOKEN\"}",
"errcode": "M_BAD_STATUS",
"error": "Ping returned status 401",
"status": 401
}
504 response
| Name | Type | Description |
|---|---|---|
errcode |
string |
Required: An error code. |
error |
string |
A human-readable error message. |
{
"errcode": "M_CONNECTION_TIMEOUT",
"error": "Connection to application service timed out"
}
使用 /sync 和 /events
希望使用客户端-服务器 API 的 /sync 或 /events 端点的应用服务,必须以虚拟用户身份访问(通过查询字符串提供 user_id)。建议应用服务通过推送事务的方式处理事件,而非以 sender_localpart 标识的用户同步。
应用服务房间目录
应用服务可为其定义的第三方协议维护独立的房间目录。这些房间目录可通过客户端-服务器 API 的 /publicRooms 端点及额外参数由客户端访问。
PUT
/_matrix/client/v3/directory/list/appservice/{networkId}/{roomId}
Updates the visibility of a given room on the application service’s room directory.
This API is similar to the room directory visibility API used by clients to update the homeserver’s more general room directory.
This API requires the use of an application service access token (as_token)
instead of a typical client’s access_token. This API cannot be invoked by
users who are not identified as application services.
| Rate-limited: | No |
|---|---|
| Requires authentication: | Yes |
Request
Request parameters
| Name | Type | Description |
|---|---|---|
networkId |
string |
Required: The protocol (network) ID to update the room list for. This would have been provided by the application service as being listed as a supported protocol. |
roomId |
string |
Required: The room ID to add to the directory. |
Request body
| Name | Type | Description |
|---|---|---|
visibility |
string |
Required: Whether the room should be visible (public) in the directory or not (private). One of: |
Request body example
{
"visibility": "public"
}
Responses
| Status | Description |
|---|---|
200 |
The room’s directory visibility has been updated. |
200 response
{}
引用来自第三方网络的消息
应用服务应在所发送事件的 content 中包含 external_url 字段,用于指示消息来源。此字段主要用于桥接其它网络(如 IRC)的应用服务,通常会提供 HTTP URL 以供引用。
如果 external_url 存在,客户端应为用户提供访问该 URL 的方式。同时,客户端应确保 URL 的协议为 https 或 http 后再使用。
事件中出现 external_url 并不必然意味着事件来自应用服务。客户端在使用该 URL 时应保持警惕,因其可能不是事件来源的合法引用。