Warning
You are viewing an unstable version of this specification. Unstable specifications may change at any time without notice. To view the current specification, please click here.
The Matrix client-server API and server-server APIs provide the means to implement a consistent self-contained federated messaging fabric. However, they provide limited means of implementing custom server-side behaviour in Matrix (e.g. gateways, filters, extensible hooks etc). The Application Service API (AS API) defines a standard API to allow such extensible functionality to be implemented irrespective of the underlying homeserver implementation.
Table of Contents
Version: unstable
No significant changes.
This version of the specification is generated from matrix-doc as of Git commit master,83e4d8c4.
For the full historical changelog, see https://github.com/matrix-org/matrix-doc/blob/master/changelogs/application_service.rst
The following other versions are also available, in reverse chronological order:
Application services are passive and can only observe events from homeserver. They can inject events into rooms they are participating in. They cannot prevent events from being sent, nor can they modify the content of the event being sent. In order to observe events from a homeserver, the homeserver needs to be configured to pass certain types of traffic to the application service. This is achieved by manually configuring the homeserver with information about the application service.
Note
Previously, application services could register with a homeserver via HTTP APIs. This was removed as it was seen as a security risk. A compromised application service could re-register for a global * regex and sniff all traffic on the homeserver. To protect against this, application services now have to register via configuration files which are linked to the homeserver configuration file. The addition of configuration files allows homeserver admins to sanity check the registration for suspicious regex strings.
Application services register "namespaces" of user IDs, room aliases and room IDs. These namespaces are represented as regular expressions. An application service is said to be "interested" in a given event if one of the IDs in the event match the regular expression provided by the application service, such as the room having an alias or ID in the relevant namespaces. Similarly, the application service is said to be interested in a given event if one of the application service's namespaced users is the target of the event, or is a joined member of the room where the event occurred.
An application service can also state whether they should be the only ones who can manage a specified namespace. This is referred to as an "exclusive" namespace. An exclusive namespace prevents humans and other application services from creating/deleting entities in that namespace. Typically, exclusive namespaces are used when the rooms represent real rooms on another service (e.g. IRC). Non-exclusive namespaces are used when the application service is merely augmenting the room itself (e.g. providing logging or searching facilities). Namespaces are represented by POSIX extended regular expressions and look like:
users: - exclusive: true regex: "@_irc_bridge_.*"
Application services may define the following namespaces (with none being explicitly required):
Name | Description |
---|---|
users | Events which are sent from certain users. |
aliases | Events which are sent in rooms with certain room aliases. |
rooms | Events which are sent in rooms with certain room IDs. |
Each individual namespace MUST declare the following fields:
Name | Description |
---|---|
exclusive | Required A true or false value stating whether this application service has exclusive access to events within this namespace. |
regex | Required A regular expression defining which values this namespace includes. |
Exclusive user and alias namespaces should begin with an underscore after the sigil to avoid collisions with other users on the homeserver. Application services should additionally attempt to identify the service they represent in the reserved namespace. For example, @_irc_.* would be a good namespace to register for an application service which deals with IRC.
The registration is represented by a series of key-value pairs, which this specification will present as YAML. See below for the possible options along with their explanation:
Name | Description |
---|---|
id | Required. A unique, user-defined ID of the application service which will never change. |
url | Required. The URL for the application service. May include a path after the domain name. Optionally set to null if no traffic is required. |
as_token | Required. A unique token for application services to use to authenticate requests to Homeservers. |
hs_token | Required. A unique token for Homeservers to use to authenticate requests to application services. |
sender_localpart | Required. The localpart of the user associated with the application service. |
namespaces | Required. A list of users, aliases and rooms namespaces that the application service controls. |
rate_limited | Whether requests from masqueraded users are rate-limited. The sender is excluded. |
protocols | The external protocols which the application service provides (e.g. IRC). |
An example registration file for an IRC-bridging application service is below:
id: "IRC Bridge" url: "http://127.0.0.1:1234" as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e" sender_localpart: "_irc_bot" # Will result in @_irc_bot:example.org namespaces: users: - exclusive: true regex: "@_irc_bridge_.*" aliases: - exclusive: false regex: "#_irc_bridge_.*" rooms: []
Warning
If the homeserver in question has multiple application services, each as_token and id MUST be unique per application service as these are used to identify the application service. The homeserver MUST enforce this.
Homeservers MUST include a query parameter named access_token containing the hs_token from the application service's registration when making requests to the application service. Application services MUST verify the provided access_token matches their known hs_token, failing the request with a M_FORBIDDEN error if it does not match.
Previous drafts of the application service specification had a mix of endpoints that have been used in the wild for a significant amount of time. The application service specification now defines a version on all endpoints to be more compatible with the rest of the Matrix specification and the future.
Homeservers should attempt to use the specified endpoints first when communicating with application services. However, if the application service receives an http status code that does not indicate success (ie: 404, 500, 501, etc) then the homeserver should fall back to the older endpoints for the application service.
The older endpoints have the exact same request body and response format, they just belong at a different path. The equivalent path for each is as follows:
Homeservers should periodically try again for the newer endpoints because the application service may have been updated.
The application service API provides a transaction API for sending a list of events. Each list of events includes a transaction ID, which works as follows:
Typical HS ---> AS : Homeserver sends events with transaction ID T. <--- : Application Service sends back 200 OK. AS ACK Lost HS ---> AS : Homeserver sends events with transaction ID T. <-/- : AS 200 OK is lost. HS ---> AS : Homeserver retries with the same transaction ID of T. <--- : Application Service sends back 200 OK. If the AS had processed these events already, it can NO-OP this request (and it knows if it is the same events based on the transaction ID).
The events sent to the application service should be linearised, as if they were from the event stream. The homeserver MUST maintain a queue of transactions to send to the application service. If the application service cannot be reached, the homeserver SHOULD backoff exponentially until the application service is reachable again. As application services cannot modify the events in any way, these requests can be made without blocking other aspects of the homeserver. Homeservers MUST NOT alter (e.g. add more) events they were going to send within that transaction ID on retries, as the application service may have already processed the events.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
txnId | string | Required. The transaction ID for this set of events. Homeservers generate these IDs and they are used to ensure idempotency of requests. |
JSON body parameters | ||
events | [Event] | Required. A list of events, formatted as per the Client-Server API. |
Example request:
PUT /_matrix/app/v1/transactions/35 HTTP/1.1 Content-Type: application/json { "events": [ { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" }, { "content": { "body": "This is an example text message", "msgtype": "m.text", "format": "org.matrix.custom.html", "formatted_body": "<b>This is an example text message</b>" }, "type": "m.room.message", "event_id": "$143273582443PhrSn:example.org", "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ] }
Response:
Status code 200:
The transaction was processed successfully.
Example
{}
The application service API includes two querying APIs: for room aliases and for user IDs. The application service SHOULD create the queried entity if it desires. During this process, the application service is blocking the homeserver until the entity is created and configured. If the homeserver does not receive a response to this request, the homeserver should retry several times before timing out. This should result in an HTTP status 408 "Request Timeout" on the client which initiated this request (e.g. to join a room alias).
Rationale
Blocking the homeserver and expecting the application service to create the entity using the client-server API is simpler and more flexible than alternative methods such as returning an initial sync style JSON blob and get the HS to provision the room/user. This also meant that there didn't need to be a "backchannel" to inform the application service about information about the entity such as room ID to room alias mappings.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user ID being queried. |
Example request:
GET /_matrix/app/v1/users/%40alice%3Aexample.com HTTP/1.1
Responses:
Status code 200:
The application service indicates that this user exists. The application service MUST create the user using the client-server API.
Example
{}
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" }
Status code 404:
The application service indicates that this user does not exist. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomAlias | string | Required. The room alias being queried. |
Example request:
GET /_matrix/app/v1/rooms/%23magicforest%3Aexample.com HTTP/1.1
Responses:
Status code 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.
Example
{}
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" }
Status code 404:
The application service indicates that this room alias does not exist. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
Application services may declare which protocols they support via their registration configuration for the homeserver. These networks are generally for third party services such as IRC that the application service is managing. Application services may populate a Matrix room directory for their registered protocols, as defined in the Client-Server API Extensions.
Each protocol may have several "locations" (also known as "third party locations" or "3PLs"). A location within a protocol is a place in the third party network, such as an IRC channel. Users of the third party network may also be represented by the application service.
Locations and users can be searched by fields defined by the application service, such as by display name or other attribute. When clients request the homeserver to search in a particular "network" (protocol), the search fields will be passed along to the application service for filtering.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
protocol | string | Required. The protocol ID. |
Response format:
Parameter | Type | Description |
---|---|---|
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. |
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. |
icon | string | Required. A content URI representing an icon for the third party protocol. |
field_types | Field Types | Required. The type definitions for the fields defined in the user_fields and location_fields. Each entry in those arrays MUST have an entry here. The string key for this object is field name itself. May be an empty object if no fields are defined. |
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. |
Parameter | Type | Description |
---|---|---|
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. |
placeholder | string | Required. An placeholder serving as a valid example of the field value. |
Parameter | Type | Description |
---|---|---|
desc | string | Required. A human-readable description for the protocol, such as the name. |
icon | string | An optional content URI representing the protocol. Overrides the one provided at the higher level Protocol object. |
fields | object | Required. Preset values for fields the client may use to search by. |
network_id | string | Required. A unique identifier across all instances. |
Example request:
GET /_matrix/app/v1/thirdparty/protocol/irc HTTP/1.1
Responses:
Status code 200:
The protocol was found and metadata returned.
Example
{ "irc": { "user_fields": [ "network", "nickname" ], "location_fields": [ "network", "channel" ], "icon": "mxc://example.org/aBcDeFgH", "field_types": { "network": { "regexp": "([a-z0-9]+\\.)*[a-z0-9]+", "placeholder": "irc.example.org" }, "nickname": { "regexp": "[^\\s]+", "placeholder": "username" }, "channel": { "regexp": "#[^\\s]+", "placeholder": "#foobar" } }, "instances": [ { "network_id": "freenode", "desc": "Freenode", "icon": "mxc://example.org/JkLmNoPq", "fields": { "network": "freenode.net" } } ] }, "gitter": { "user_fields": [ "username" ], "location_fields": [ "room" ], "field_types": { "username": { "regexp": "@[^\\s]+", "placeholder": "@username" }, "room": { "regexp": "[^\\s]+\\/[^\\s]+", "placeholder": "matrix-org/matrix-doc" } }, "instances": [ { "network_id": "gitter", "desc": "Gitter", "icon": "mxc://example.org/zXyWvUt", "fields": {} } ] } }
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" }
Status code 404:
No protocol was found with the given path.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
protocol | string | Required. The protocol ID. |
query parameters | ||
fields... | string | One or more custom fields that are passed to the application service to help identify the user. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | [User] | List of matched third party users. |
Parameter | Type | Description |
---|---|---|
userid | string | Required. A Matrix User ID represting a third party user. |
protocol | string | Required. The protocol ID that the third party location is a part of. |
fields | object | Required. Information used to identify this third party location. |
Example request:
GET /_matrix/app/v1/thirdparty/user/irc HTTP/1.1
Responses:
Status code 200:
The Matrix User IDs found with the given parameters.
Example
[ { "userid": "@_gitter_jim:matrix.org", "protocol": "gitter", "fields": { "user": "jim" } } ]
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" }
Status code 404:
No users were found with the given parameters.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
Retrieve a list of Matrix portal rooms that lead to the matched third party location.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
protocol | string | Required. The protocol ID. |
query parameters | ||
fields... | string | One or more custom fields that are passed to the application service to help identify the third party location. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | [Location] | List of matched third party locations. |
Parameter | Type | Description |
---|---|---|
alias | string | Required. An alias for a matrix room. |
protocol | string | Required. The protocol ID that the third party location is a part of. |
fields | object | Required. Information used to identify this third party location. |
Example request:
GET /_matrix/app/v1/thirdparty/location/irc HTTP/1.1
Responses:
Status code 200:
At least one portal room was found.
Example
[ { "alias": "#freenode_#matrix:matrix.org", "protocol": "irc", "fields": { "network": "freenode", "channel": "#matrix" } } ]
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" }
Status code 404:
No mappings were found with the given parameters.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
Retrieve an array of third party network locations from a Matrix room alias.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
alias | string | The Matrix room alias to look up. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | [Location] | List of matched third party locations. |
Parameter | Type | Description |
---|---|---|
alias | string | Required. An alias for a matrix room. |
protocol | string | Required. The protocol ID that the third party location is a part of. |
fields | object | Required. Information used to identify this third party location. |
Example request:
GET /_matrix/app/v1/thirdparty/location HTTP/1.1
Responses:
Status code 200:
All found third party locations.
Example
[ { "alias": "#freenode_#matrix:matrix.org", "protocol": "irc", "fields": { "network": "freenode", "channel": "#matrix" } } ]
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" }
Status code 404:
No mappings were found with the given parameters.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
Retrieve an array of third party users from a Matrix User ID.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
userid | string | The Matrix User ID to look up. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | [User] | List of matched third party users. |
Parameter | Type | Description |
---|---|---|
userid | string | Required. A Matrix User ID represting a third party user. |
protocol | string | Required. The protocol ID that the third party location is a part of. |
fields | object | Required. Information used to identify this third party location. |
Example request:
GET /_matrix/app/v1/thirdparty/user HTTP/1.1
Responses:
Status code 200:
An array of third party users.
Example
[ { "userid": "@_gitter_jim:matrix.org", "protocol": "gitter", "fields": { "user": "jim" } } ]
Status code 401:
The homeserver has not supplied credentials to the application service. Optional error information can be included in the body of this response.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 403:
The credentials supplied by the homeserver were rejected.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" }
Status code 404:
No mappings were found with the given parameters.
Example
{ "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" }
Application services can use a more powerful version of the client-server API by identifying itself as an application service to the homeserver.
Endpoints defined in this section MUST be supported by homeservers in the client-server API as accessible only by application services.
The client-server API infers the user ID from the access_token provided in every request. To avoid the application service from having to keep track of each user's access token, the application service should identify itself to the Client-Server API by providing its as_token for the access_token alongside the user the application service would like to masquerade as.
The application service may specify the virtual user to act as through use of a user_id query string parameter on the request. The user specified in the query string must be covered by one of the application service's user namespaces. If the parameter is missing, the homeserver is to assume the application service intends to act as the user implied by the sender_localpart property of the registration.
An example request would be:
GET /_matrix/client/r0/account/whoami?user_id=@_irc_user:example.org Authorization: Bearer YourApplicationServiceTokenHere
Previous drafts of the Application Service API permitted application services to alter the timestamp of their sent events by providing a ts query parameter when sending an event. This API has been excluded from the first release due to design concerns, however some servers may still support the feature. Please visit issue #1585 for more information.
The homeserver needs to give the application service full control over its namespace, both for users and for room aliases. This means that the AS should be able to create/edit/delete any room alias in its namespace, as well as create/delete any user in its namespace. No additional API changes need to be made in order for control of room aliases to be granted to the AS. Creation of users needs API changes in order to:
This involves bypassing the registration flows entirely. This is achieved by including the as_token on a /register request, along with a login type of m.login.application_service to set the desired user ID without a password.
POST /_matrix/client/r0/register Authorization: Bearer YourApplicationServiceTokenHere Content: { type: "m.login.application_service", username: "_irc_example" }
Application services which attempt to create users or aliases outside of their defined namespaces will receive an error code M_EXCLUSIVE. Similarly, normal users who attempt to create users or aliases inside an application service-defined namespace will receive the same M_EXCLUSIVE error code, but only if the application service has defined the namespace as exclusive.
Application services wishing to use /sync or /events from the Client-Server API MUST do so with a virtual user (provide a user_id via the query string). It is expected that the application service use the transactions pushed to it to handle events rather than syncing with the user implied by sender_localpart.
Application services can maintain their own room directories for their defined third party protocols. These room directories may be accessed by clients through additional parameters on the /publicRooms client-server endpoint.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
JSON body parameters | ||
visibility | enum | Required. Whether the room should be visible (public) in the directory or not (private). One of: ["public", "private"] |
Example request:
PUT /_matrix/client/r0/directory/list/appservice/irc/%21somewhere%3Aexample.org HTTP/1.1 Content-Type: application/json { "visibility": "public" }
Response:
Status code 200:
The room's directory visibility has been updated.
Example
{}
Application services should include an external_url in the content of events it emits to indicate where the message came from. This typically applies to application services that bridge other networks into Matrix, such as IRC, where an HTTP URL may be available to reference.
Clients should provide users with a way to access the external_url if it is present. Clients should additionally ensure the URL has a scheme of https or http before making use of it.
The presence of an external_url on an event does not necessarily mean the event was sent from an application service. Clients should be wary of the URL contained within, as it may not be a legitimate reference to the event's source.