Warning
You are viewing an outdated version of this specification. To view the current specification, please click here.
The client-server API provides a simple lightweight API to let clients send messages, control rooms and synchronise conversation history. It is designed to support both lightweight clients which store no state and lazy-load data from the server as required - as well as heavyweight clients which maintain a full local persistent copy of server state.
Table of Contents
Version: r0.5.0
Breaking Changes
Deprecations
New Endpoints
Backwards Compatible Changes
Spec Clarifications
This version of the specification is generated from matrix-doc as of Git commit master,19a3d574.
For the full historical changelog, see https://github.com/matrix-org/matrix-doc/blob/main/changelogs/legacy/client_server.rst
The following other versions are also available, in reverse chronological order:
The mandatory baseline for client-server communication in Matrix is exchanging JSON objects over HTTP APIs. HTTPS is recommended for communication, although HTTP may be supported as a fallback to support basic HTTP clients. More efficient optional transports will in future be supported as optional extensions - e.g. a packed binary encoding over stream-cipher encrypted TCP socket for low-bandwidth/low-roundtrip mobile usage. For the default HTTP transport, all API calls use a Content-Type of application/json. In addition, all strings MUST be encoded as UTF-8. Clients are authenticated using opaque access_token strings (see Client Authentication for details), passed as a query string parameter on all requests.
The names of the API endpoints for the HTTP transport follow a convention of using underscores to separate words (for example /delete_devices). The key names in JSON objects passed over the API also follow this convention.
Note
There are a few historical exceptions to this rule, such as /createRoom. A future version of this specification will address the inconsistency.
Any errors which occur at the Matrix API level MUST return a "standard error response". This is a JSON object which looks like:
{ "errcode": "<error code>", "error": "<error message>" }
The error string will be a human-readable error message, usually a sentence explaining what went wrong. The errcode string will be a unique string which can be used to handle an error message e.g. M_FORBIDDEN. These error codes should have their namespace first in ALL CAPS, followed by a single _ to ease separating the namespace from the error code. For example, if there was a custom namespace com.mydomain.here, and a FORBIDDEN code, the error code should look like COM.MYDOMAIN.HERE_FORBIDDEN. There may be additional keys depending on the error, but the keys error and errcode MUST always be present.
Errors are generally best expressed by their error code rather than the HTTP status code returned. When encountering the error code M_UNKNOWN, clients should prefer the HTTP status code as a more reliable reference for what the issue was. For example, if the client receives an error code of M_NOT_FOUND but the request gave a 400 Bad Request status code, the client should treat the error as if the resource was not found. However, if the client were to receive an error code of M_UNKNOWN with a 400 Bad Request, the client should assume that the request being made was invalid.
The common error codes are:
M_FORBIDDEN: | Forbidden access, e.g. joining a room without permission, failed login. |
---|---|
M_UNKNOWN_TOKEN: | |
The access token specified was not recognised. | |
M_MISSING_TOKEN: | |
No access token was specified for the request. | |
M_BAD_JSON: | Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. |
M_NOT_JSON: | Request did not contain valid JSON. |
M_NOT_FOUND: | No resource was found for this request. |
M_LIMIT_EXCEEDED: | |
Too many requests have been sent in a short period of time. Wait a while then try again. | |
M_UNKNOWN: | An unknown error has occurred. |
Other error codes the client might encounter are:
M_UNRECOGNIZED: | The server did not understand the request. |
---|---|
M_UNAUTHORIZED: | The request was not correctly authorized. Usually due to login failures. |
M_USER_IN_USE: | Encountered when trying to register a user ID which has been taken. |
M_INVALID_USERNAME: | |
Encountered when trying to register a user ID which is not valid. | |
M_ROOM_IN_USE: | Sent when the room alias given to the createRoom API is already in use. |
M_INVALID_ROOM_STATE: | |
Sent when the initial state given to the createRoom API is invalid. | |
M_THREEPID_IN_USE: | |
Sent when a threepid given to an API cannot be used because the same threepid is already in use. | |
M_THREEPID_NOT_FOUND: | |
Sent when a threepid given to an API cannot be used because no record matching the threepid was found. | |
M_THREEPID_AUTH_FAILED: | |
Authentication could not be performed on the third party identifier. | |
M_THREEPID_DENIED: | |
The server does not permit this third party identifier. This may happen if the server only permits, for example, email addresses from a particular domain. | |
M_SERVER_NOT_TRUSTED: | |
The client's request used a third party server, eg. identity server, that this server does not trust. | |
M_UNSUPPORTED_ROOM_VERSION: | |
The client's request to create a room used a room version that the server does not support. | |
M_INCOMPATIBLE_ROOM_VERSION: | |
The client attempted to join a room that has a version the server does not support. Inspect the room_version property of the error response for the room's version. | |
M_BAD_STATE: | The state change requested cannot be performed, such as attempting to unban a user who is not banned. |
M_GUEST_ACCESS_FORBIDDEN: | |
The room or resource does not permit guests to access it. | |
M_CAPTCHA_NEEDED: | |
A Captcha is required to complete the request. | |
M_CAPTCHA_INVALID: | |
The Captcha provided did not match what was expected. | |
M_MISSING_PARAM: | |
A required parameter was missing from the request. | |
M_INVALID_PARAM: | |
A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. | |
M_TOO_LARGE: | The request or entity was too large. |
M_EXCLUSIVE: | The resource being requested is reserved by an application service, or the application service making the request has not created the resource. |
M_RESOURCE_LIMIT_EXCEEDED: | |
The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example, a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account data, etc) and not routes which only read state (eg: /sync, get account data, etc). | |
M_CANNOT_LEAVE_SERVER_NOTICE_ROOM: | |
The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. |
The client-server API typically uses HTTP PUT to submit requests with a client-generated transaction identifier. This means that these requests are idempotent. The scope of a transaction identifier is a particular access token. It only serves to identify new requests from retransmits. After the request has finished, the {txnId} value should be changed (how is not specified; a monotonically increasing integer is recommended).
Some API endpoints may allow or require the use of POST requests without a transaction ID. Where this is optional, the use of a PUT request is strongly recommended.
Gets the versions of the specification supported by the server.
Values will take the form rX.Y.Z.
Only the latest Z value will be reported for each supported X.Y value. i.e. if the server implements r0.0.0, r0.0.1, and r1.2.0, it will report r0.0.1 and r1.2.0.
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 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 auth: | No. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
versions | [string] | Required. The supported versions. |
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. |
Example request:
GET /_matrix/client/versions HTTP/1.1
Response:
Status code 200:
The versions supported by the server.
Example
{ "versions": [ "r0.0.1" ], "unstable_features": { "org.example.my_feature": true } }
It is realistic to expect that some clients will be written to be run within a web browser or similar environment. In these cases, the homeserver should respond to pre-flight requests and supply Cross-Origin Resource Sharing (CORS) headers on all requests.
Servers MUST expect that clients will approach them with OPTIONS requests, allowing clients to discover the CORS headers. All endpoints in this specification s upport the OPTIONS method, however the server MUST NOT perform any logic defined for the endpoints when approached with an OPTIONS request.
When a client approaches the server with a request, the server should respond with the CORS headers for that route. The recommended CORS headers to be returned by servers on all requests are:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
In order to allow users to connect to a Matrix server without needing to explicitly specify the homeserver's URL or other parameters, clients SHOULD use an auto-discovery mechanism to determine the server's URL based on a user's Matrix ID. Auto-discovery should only be done at login time.
In this section, the following terms are used with specific meanings:
Note
Servers hosting the .well-known JSON file SHOULD offer CORS headers, as per the CORS section in this specification.
The .well-known method uses a JSON file at a predetermined location to specify parameter values. The flow for this method is as follows:
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 auth: | No. |
Request format:
No parameters
Response format:
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
base_url | string | Required. The base URL for the homeserver for client-server connections. |
Parameter | Type | Description |
---|---|---|
base_url | string | Required. The base URL for the identity server for client-server connections. |
Example request:
GET /.well-known/matrix/client HTTP/1.1
Responses:
Status code 200:
Server discovery information.
Example
{ "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" } }
Status code 404:
No server discovery information available.
Most API endpoints require the user to identify themselves by presenting previously obtained credentials in the form of an access_token query parameter or through an Authorization Header of Bearer $access_token. An access token is typically obtained via the Login or Registration processes.
Note
This specification does not mandate a particular format for the access token. Clients should treat it as an opaque byte sequence. Servers are free to choose an appropriate format. Server implementors may like to investigate macaroons.
Access tokens may be provided in two ways, both of which the homeserver MUST support:
Clients are encouraged to use the Authorization header where possible to prevent the access token being leaked in access/HTTP logs. The query string should only be used in cases where the Authorization header is inaccessible for the client.
When credentials are required but missing or invalid, the HTTP call will return with a status of 401 and the error code, M_MISSING_TOKEN or M_UNKNOWN_TOKEN respectively.
Client devices are closely related to access tokens. Matrix servers should record which device each access token is assigned to, so that subsequent requests can be handled correctly.
By default, the Login and Registration processes auto-generate a new device_id. A client is also free to generate its own device_id or, provided the user remains the same, reuse a device: in either case the client should pass the device_id in the request body. If the client sets the device_id, the server will invalidate any access token previously assigned to that device. There is therefore at most one active access token assigned to each device at any one time.
Some API endpoints require authentication that interacts with the user. The homeserver may provide many different ways of authenticating, such as user/password auth, login via a social network (OAuth2), login by confirming a token sent to their email address, etc. This specification does not define how homeservers should authorise their users but instead defines the standard interface which implementations should follow so that ANY client can login to ANY homeserver.
The process takes the form of one or more 'stages'. At each stage the client submits a set of data for a given authentication type and awaits a response from the server, which will either be a final success or a request to perform an additional stage. This exchange continues until the final success.
For each endpoint, a server offers one or more 'flows' that the client can use to authenticate itself. Each flow comprises a series of stages, as described above. The client is free to choose which flow it follows, however the flow's stages must be completed in order. Failing to follow the flows in order must result in an HTTP 401 response, as defined below. When all stages in a flow are complete, authentication is complete and the API call succeeds.
In the REST API described in this specification, authentication works by the client and server exchanging JSON dictionaries. The server indicates what authentication data it requires via the body of an HTTP 401 response, and the client submits that authentication data via the auth request parameter.
A client should first make a request with no auth parameter [1]. The homeserver returns an HTTP 401 response, with a JSON body, as follows:
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" }
In addition to the flows, this object contains some extra information:
The client then chooses a flow and attempts to complete the first stage. It does this by resubmitting the same request with the addition of an auth key in the object that it submits. This dictionary contains a type key whose value is the name of the authentication type that the client is attempting to complete. It must also contain a session key with the value of the session key given by the homeserver, if one was given. It also contains other keys dependent on the auth type being attempted. For example, if the client is attempting to complete auth type example.type.foo, it might submit something like this:
POST /_matrix/client/r0/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" } }
If the homeserver deems the authentication attempt to be successful but still requires more stages to be completed, it returns HTTP status 401 along with the same object as when no authentication was attempted, with the addition of the completed key which is an array of auth types the client has completed successfully:
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" }
Individual stages may require more than one request to complete, in which case the response will be as if the request was unauthenticated with the addition of any other keys as defined by the auth type.
If the homeserver decides that an attempt on a stage was unsuccessful, but the client may make a second attempt, it returns the same HTTP status 401 response as above, with the addition of the standard errcode and error fields describing the error. For example:
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" }
If the request fails for a reason other than authentication, the server returns an error message in the standard format. For example:
HTTP/1.1 400 Bad request Content-Type: application/json { "errcode": "M_EXAMPLE_ERROR", "error": "Something was wrong" }
If the client has completed all stages of a flow, the homeserver performs the API call and returns the result as normal. Completed stages cannot be retried by clients, therefore servers must return either a 401 response with the completed stages, or the result of the API call if all stages were completed when a client retries a stage.
Some authentication types may be completed by means other than through the Matrix client, for example, an email confirmation may be completed when the user clicks on the link in the email. In this case, the client retries the request with an auth dict containing only the session key. The response to this will be the same as if the client were attempting to complete an auth state normally, i.e. the request will either complete or request auth, with the presence or absence of that auth type in the 'completed' array indicating whether that stage is complete.
[1] | A request to an endpoint that uses User-Interactive Authentication never succeeds without auth. Homeservers may allow requests that don't require auth by offering a stage with only the m.login.dummy auth type, but they must still give a 401 response to requests with no auth data. |
At a high level, the requests made for an API call completing an auth flow with three stages will resemble the following diagram:
_______________________ | Stage 0 | | No auth | | ___________________ | | |_Request_1_________| | <-- Returns "session" key which is used throughout. |_______________________| | | _________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_________| | <-- Returns API response |_______________________|
Type: | m.login.password |
---|---|
Description: | The client submits an identifier and secret password, both sent in plain-text. |
To use this authentication type, clients should submit an auth dict as follows:
{ "type": "m.login.password", "identifier": { ... }, "password": "<password>", "session": "<session ID>" }
where the identifier property is a user identifier object, as described in Identifier types.
For example, to authenticate using the user's Matrix ID, clients would submit:
{ "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "<user_id or user localpart>" }, "password": "<password>", "session": "<session ID>" }
Alternatively reply using a 3PID bound to the user's account on the homeserver using the /account/3pid API rather then giving the user explicitly as follows:
{ "type": "m.login.password", "identifier": { "type": "m.id.thirdparty", "medium": "<The medium of the third party identifier.>", "address": "<The third party address of the user>" }, "password": "<password>", "session": "<session ID>" }
In the case that the homeserver does not know about the supplied 3PID, the homeserver must respond with 403 Forbidden.
Type: | m.login.recaptcha |
---|---|
Description: | The user completes a Google ReCaptcha 2.0 challenge |
To use this authentication type, clients should submit an auth dict as follows:
{ "type": "m.login.recaptcha", "response": "<captcha response>", "session": "<session ID>" }
Type: | m.login.token |
---|---|
Description: | The client submits a login token. |
To use this authentication type, clients should submit an auth dict as follows:
{ "type": "m.login.token", "token": "<token>", "txn_id": "<client generated nonce>", "session": "<session ID>" }
The nonce should be a random string generated by the client for the request. The same nonce should be used if retrying the request.
A client may receive a login token via some external service, such as email or SMS. Note that a login token is separate from an access token, the latter providing general authentication to various API endpoints.
The txn_id may be used by the server to disallow other devices from using the token, thus providing "single use" tokens while still allowing the device to retry the request. This would be done by tying the token to the txn_id server side, as well as potentially invalidating the token completely once the device has successfully logged in (e.g. when we receive a request from the newly provisioned access_token).
The server must encode the user id in the token. There is therefore no need for the client to submit a separate username.
Type: | m.login.oauth2 |
---|---|
Description: | Authentication is supported via OAuth2 URLs. This login consists of multiple requests. |
Parameters: | uri: Authorization Request URI OR service selection URI. Both contain an encoded redirect URI. |
The homeserver acts as a 'confidential' client for the purposes of OAuth2. If the uri is a service selection URI, it MUST point to a webpage which prompts the user to choose which service to authorize with. On selection of a service, this MUST link through to an Authorization Request URI. If there is only one service which the homeserver accepts when logging in, this indirection can be skipped and the "uri" key can be the Authorization Request URI.
The client then visits the Authorization Request URI, which then shows the OAuth2 Allow/Deny prompt. Hitting 'Allow' redirects to the redirect URI with the auth code. Homeservers can choose any path for the redirect URI. Once the OAuth flow has completed, the client retries the request with the session only, as above.
Type: | m.login.email.identity |
---|---|
Description: | Authentication is supported by authorising an email address with an identity server, or homeserver if supported. |
Prior to submitting this, the client should authenticate with an identity server (or homeserver). After authenticating, the session information should be submitted to the homeserver.
To use this authentication type, clients should submit an auth dict as follows:
{ "type": "m.login.email.identity", "threepidCreds": [ { "sid": "<identity server session id>", "client_secret": "<identity server client secret>", "id_server": "<url of identity server authed with, e.g. 'matrix.org:8090'>" } ], "session": "<session ID>" }
Type: | m.login.msisdn |
---|---|
Description: | Authentication is supported by authorising a phone number with an identity server, or homeserver if supported. |
Prior to submitting this, the client should authenticate with an identity server (or homeserver). After authenticating, the session information should be submitted to the homeserver.
To use this authentication type, clients should submit an auth dict as follows:
{ "type": "m.login.msisdn", "threepidCreds": [ { "sid": "<identity server session id>", "client_secret": "<identity server client secret>", "id_server": "<url of identity server authed with, e.g. 'matrix.org:8090'>" } ], "session": "<session ID>" }
Type: | m.login.dummy |
---|---|
Description: | Dummy authentication always succeeds and requires no extra parameters. Its purpose is to allow servers to not require any form of User-Interactive Authentication to perform a request. It can also be used to differentiate flows where otherwise one flow would be a subset of another flow. eg. if a server offers flows m.login.recaptcha and m.login.recaptcha, m.login.email.identity and the client completes the recaptcha stage first, the auth would succeed with the former flow, even if the client was intending to then complete the email auth stage. A server can instead send flows m.login.recaptcha, m.login.dummy and m.login.recaptcha, m.login.email.identity to fix the ambiguity. |
To use this authentication type, clients should submit an auth dict with just the type and session, if provided:
{ "type": "m.login.dummy", "session": "<session ID>" }
Clients cannot be expected to be able to know how to process every single login type. If a client does not know how to handle a given login type, it can direct the user to a web browser with the URL of a fallback page which will allow the user to complete that login step out-of-band in their web browser. The URL it should open is:
/_matrix/client/r0/auth/<auth type>/fallback/web?session=<session ID>
Where auth type is the type name of the stage it is attempting and session ID is the ID of the session given by the homeserver.
This MUST return an HTML page which can perform this authentication stage. This page must use the following JavaScript when the authentication has been completed:
if (window.onAuthDone) { window.onAuthDone(); } else if (window.opener && window.opener.postMessage) { window.opener.postMessage("authDone", "*"); }
This allows the client to either arrange for the global function onAuthDone to be defined in an embedded browser, or to use the HTML5 cross-document messaging API, to receive a notification that the authentication stage has been completed.
Once a client receives the notificaton that the authentication stage has been completed, it should resubmit the request with an auth dict with just the session ID:
{ "session": "<session ID>" }
A client webapp might use the following javascript to open a popup window which will handle unknown login types:
/** * Arguments: * homeserverUrl: the base url of the homeserver (eg "https://matrix.org") * * apiEndpoint: the API endpoint being used (eg * "/_matrix/client/r0/account/password") * * loginType: the loginType being attempted (eg "m.login.recaptcha") * * sessionID: the session ID given by the homeserver in earlier requests * * onComplete: a callback which will be called with the results of the request */ function unknownLoginType(homeserverUrl, apiEndpoint, loginType, sessionID, onComplete) { var popupWindow; var eventListener = function(ev) { // check it's the right message from the right place. if (ev.data !== "authDone" || ev.origin !== homeserverUrl) { return; } // close the popup popupWindow.close(); window.removeEventListener("message", eventListener); // repeat the request var requestBody = { auth: { session: sessionID, }, }; request({ method:'POST', url:apiEndpint, json:requestBody, }, onComplete); }; window.addEventListener("message", eventListener); var url = homeserverUrl + "/_matrix/client/r0/auth/" + encodeURIComponent(loginType) + "/fallback/web?session=" + encodeURIComponent(sessionID); popupWindow = window.open(url); }
Some authentication mechanisms use a user identifier object to identify a user. The user identifier object has a type field to indicate the type of identifier being used, and depending on the type, has other fields giving the information required to identify the user as described below.
Type: | m.id.user |
---|---|
Description: | The user is identified by their Matrix ID. |
A client can identify a user using their Matrix ID. This can either be the fully qualified Matrix user ID, or just the localpart of the user ID.
"identifier": { "type": "m.id.user", "user": "<user_id or user localpart>" }
Type: | m.id.thirdparty |
---|---|
Description: | The user is identified by a third-party identifier in canonicalised form. |
A client can identify a user using a 3PID associated with the user's account on the homeserver, where the 3PID was previously associated using the /account/3pid API. See the 3PID Types Appendix for a list of Third-party ID media.
"identifier": { "type": "m.id.thirdparty", "medium": "<The medium of the third party identifier>", "address": "<The canonicalised third party address of the user>" }
Type: | m.id.phone |
---|---|
Description: | The user is identified by a phone number. |
A client can identify a user using a phone number associated with the user's account, where the phone number was previously associated using the /account/3pid API. The phone number can be passed in as entered by the user; the homeserver will be responsible for canonicalising it. If the client wishes to canonicalise the phone number, then it can use the m.id.thirdparty identifier type with a medium of msisdn instead.
"identifier": { "type": "m.id.phone", "country": "<The country that the phone number is from>", "phone": "<The phone number>" }
A client can obtain access tokens using the /login API.
Note that this endpoint does not currently use the user-interactive authentication API.
For a simple username/password login, clients should submit a /login request as follows:
{ "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "<user_id or user localpart>" }, "password": "<password>" }
Alternatively, a client can use a 3PID bound to the user's account on the homeserver using the /account/3pid API rather then giving the user explicitly, as follows:
{ "type": "m.login.password", "identifier": { "medium": "<The medium of the third party identifier>", "address": "<The canonicalised third party address of the user>" }, "password": "<password>" }
In the case that the homeserver does not know about the supplied 3PID, the homeserver must respond with 403 Forbidden.
To log in using a login token, clients should submit a /login request as follows:
{ "type": "m.login.token", "token": "<login token>" }
As with token-based interactive login, the token must encode the user ID. In the case that the token is not valid, the homeserver must respond with 403 Forbidden and an error code of M_FORBIDDEN.
If the homeserver advertises m.login.sso as a viable flow, and the client supports it, the client should redirect the user to the /redirect endpoint for Single Sign-On. After authentication is complete, the client will need to submit a /login request matching m.login.token.
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 auth: | No. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
flows | [LoginFlow] | The homeserver's supported login types |
Parameter | Type | Description |
---|---|---|
type | string | The login type. This is supplied as the type when logging in. |
Example request:
GET /_matrix/client/r0/login HTTP/1.1
Responses:
Status code 200:
The login types the homeserver supports
Example
{ "flows": [ { "type": "m.login.password" } ] }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
type | enum | Required. The login type being used. One of: ["m.login.password", "m.login.token"] |
identifier | User identifier | Identification information for the user. |
user | string | The fully qualified user ID or just local part of the user ID, to log in. Deprecated in favour of identifier. |
medium | string | When logging in using a third party identifier, the medium of the identifier. Must be 'email'. Deprecated in favour of identifier. |
address | string | Third party identifier for the user. Deprecated in favour of identifier. |
password | string | Required when type is m.login.password. The user's password. |
token | string | Required when type is m.login.token. Part of Token-based login. |
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. |
initial_device_display_name | string | A display name to assign to the newly-created device. Ignored if device_id corresponds to a known device. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The type of identification. See Identifier types for supported values and additional property descriptions. |
Response format:
Parameter | Type | Description |
---|---|---|
user_id | string | The fully-qualified Matrix ID that has been registered. |
access_token | string | An access token for the account. This access token can then be used to authorize other requests. |
home_server | string | 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. |
device_id | string | ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified. |
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. |
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
base_url | string | Required. The base URL for the homeserver for client-server connections. |
Parameter | Type | Description |
---|---|---|
base_url | string | Required. The base URL for the identity server for client-server connections. |
Example request:
POST /_matrix/client/r0/login HTTP/1.1 Content-Type: application/json { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "cheeky_monkey" }, "password": "ilovebananas", "initial_device_display_name": "Jungle Phone" }
Responses:
Status code 200:
The user has been authenticated.
Example
{ "user_id": "@cheeky_monkey:matrix.org", "access_token": "abc123", "device_id": "GHTYAJCE", "well_known": { "m.homeserver": { "base_url": "https://example.org" }, "m.identity_server": { "base_url": "https://id.example.org" } } }
Status code 400:
Part of the request was invalid. For example, the login type may not be recognised.
Example
{ "errcode": "M_UNKNOWN", "error": "Bad login type." }
Status code 403:
The login attempt failed. For example, the password may have been incorrect.
Example
{ "errcode": "M_FORBIDDEN" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | Yes. |
Request format:
No parameters
Example request:
POST /_matrix/client/r0/logout HTTP/1.1
Response:
Status code 200:
The access token used in the request was succesfully invalidated.
Example
{}
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 require UI authorization because UI authorization 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 auth: | Yes. |
Request format:
No parameters
Example request:
POST /_matrix/client/r0/logout/all HTTP/1.1
Response:
Status code 200:
The user's access tokens were succesfully invalidated.
Example
{}
If a client does not recognize any or all login flows it can use the fallback login API:
GET /_matrix/static/client/login/
This returns an HTML and JavaScript page which can perform the entire login process. The page will attempt to call the JavaScript function window.onLogin when login has been successfully completed.
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:
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 usernames which do 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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
kind | enum | The kind of account to register. Defaults to user. One of: ["guest", "user"] |
JSON body parameters | ||
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. |
bind_email | boolean | If true, the server binds the email used for authentication to the Matrix ID with the identity server. |
bind_msisdn | boolean | If true, the server binds the phone number used for authentication to the Matrix ID with the identity server. |
username | string | The basis for the localpart of the desired Matrix ID. If omitted, the homeserver MUST generate a Matrix ID local part. |
password | string | The desired password for the account. |
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. |
initial_device_display_name | string | A display name to assign to the newly-created device. Ignored if device_id corresponds to a known device. |
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. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The login type that the client is attempting to complete. |
session | string | The value of the session key given by the homeserver. |
Response format:
Parameter | Type | Description |
---|---|---|
user_id | string | 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 | 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. |
home_server | string | 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. |
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. |
Example request:
POST /_matrix/client/r0/register?kind=user HTTP/1.1 Content-Type: application/json { "auth": { "type": "example.type.foo", "session": "xxxxx", "example_credential": "verypoorsharedsecret" }, "bind_email": false, "bind_msisdn": false, "username": "cheeky_monkey", "password": "ilovebananas", "device_id": "GHTYAJCE", "initial_device_display_name": "Jungle Phone", "inhibit_login": false }
Responses:
Status code 200:
The account has been registered.
Example
{ "user_id": "@cheeky_monkey:matrix.org", "access_token": "abc123", "device_id": "GHTYAJCE" }
Status code 400:
Part of the request was invalid. This may include one of the following error codes:
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.
Example
{ "errcode": "M_USER_IN_USE", "error": "Desired user ID is already taken." }
Status code 401:
The homeserver requires additional authentication information.
Example
{ "flows": [ { "stages": [ "example.type.foo" ] } ], "params": { "example.type.baz": { "example_key": "foobar" } }, "session": "xxxxxxyz", "completed": [ "example.type.foo" ] }
Status code 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.
Example
{ "errcode": "M_FORBIDDEN", "error": "Registration is disabled" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
The homeserver must check that the given email address is not already associated with an account on this homeserver. The homeserver has the choice of validating the email address itself, or proxying the request to the /validate/email/requestToken Identity Service API. The request should be proxied to the domain that is sent by the client in the id_server. It is imperative that the homeserver keep a list of trusted Identity Servers and only proxies to those it trusts.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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. |
string | Required. The email address to validate. | |
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. |
next_link | string | 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. |
id_server | string | Required. The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification. |
Response format:
Parameter | 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 | string | 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. 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). |
Example request:
POST /_matrix/client/r0/register/email/requestToken HTTP/1.1 Content-Type: application/json { "client_secret": "monkeys_are_GREAT", "email": "foo@example.com", "send_attempt": 1 }
Responses:
Status code 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.
Example
{ "sid": "123abc", "submit_url": "https://example.org/path/to/submitToken" }
Status code 400:
Part of the request was invalid. This may include one of the following error codes:
Example
{ "errcode": "M_THREEPID_IN_USE", "error": "The specified address is already in use" }
Status code 403:
The homeserver does not permit the address to be bound.
Example
{ "errcode": "M_THREEPID_DENIED", "error": "Third party identifier is not allowed" }
The homeserver must check that the given phone number is not already associated with an account on this homeserver. The homeserver has the choice of validating the phone number itself, or proxying the request to the /validate/msisdn/requestToken Identity Service API. The request should be proxied to the domain that is sent by the client in the id_server. It is imperative that the homeserver keep a list of trusted Identity Servers and only proxies to those it trusts.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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 country code that the number in phone_number should be parsed as if it were dialled from. |
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. |
next_link | string | 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. |
id_server | string | Required. The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification. |
Response format:
Parameter | 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 | string | 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. 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). |
Example request:
POST /_matrix/client/r0/register/msisdn/requestToken HTTP/1.1 Content-Type: application/json { "client_secret": "monkeys_are_GREAT", "country": "GB", "phone_number": "07700900001", "send_attempt": 1 }
Responses:
Status code 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.
Example
{ "sid": "123abc", "submit_url": "https://example.org/path/to/submitToken" }
Status code 400:
Part of the request was invalid. This may include one of the following error codes:
Example
{ "errcode": "M_THREEPID_IN_USE", "error": "The specified address is already in use" }
Status code 403:
The homeserver does not permit the address to be bound.
Example
{ "errcode": "M_THREEPID_DENIED", "error": "Third party identifier is not allowed" }
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, however all other access tokens for the user should be revoked if the request succeeds.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
new_password | string | Required. The new password for the account. |
auth | Authentication Data | Additional authentication information for the user-interactive authentication API. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The login type that the client is attempting to complete. |
session | string | The value of the session key given by the homeserver. |
Example request:
POST /_matrix/client/r0/account/password HTTP/1.1 Content-Type: application/json { "new_password": "ihatebananas", "auth": { "type": "example.type.foo", "session": "xxxxx", "example_credential": "verypoorsharedsecret" } }
Responses:
Status code 200:
The password has been changed.
Example
{}
Status code 401:
The homeserver requires additional authentication information.
Example
{ "flows": [ { "stages": [ "example.type.foo" ] } ], "params": { "example.type.baz": { "example_key": "foobar" } }, "session": "xxxxxxyz", "completed": [ "example.type.foo" ] }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 has the choice of validating the email address itself, or proxying the request to the /validate/email/requestToken Identity Service API. The request should be proxied to the domain that is sent by the client in the id_server. It is imperative that the homeserver keep a list of trusted Identity Servers and only proxies to those that it trusts.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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. |
string | Required. The email address to validate. | |
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. |
next_link | string | 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. |
id_server | string | Required. The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification. |
Response format:
Parameter | 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 | string | 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. 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). |
Example request:
POST /_matrix/client/r0/account/password/email/requestToken HTTP/1.1 Content-Type: application/json { "client_secret": "monkeys_are_GREAT", "email": "foo@example.com", "send_attempt": 1 }
Responses:
Status code 200:
An email was sent to the given address.
Example
{ "sid": "123abc", "submit_url": "https://example.org/path/to/submitToken" }
Status code 400:
The referenced third party identifier is not recognised by the homeserver, or the request was invalid
Example
{ "errcode": "M_THREEPID_NOT_FOUND", "error": "Email not found" }
Status code 403:
The homeserver does not allow the third party identifier as a contact option.
Example
{ "errcode": "M_THREEPID_DENIED", "error": "Third party identifier is not allowed" }
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 has the choice of validating the phone number itself, or proxying the request to the /validate/msisdn/requestToken Identity Service API. The request should be proxied to the domain that is sent by the client in the id_server. It is imperative that the homeserver keep a list of trusted Identity Servers and only proxies to those that it trusts.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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 country code that the number in phone_number should be parsed as if it were dialled from. |
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. |
next_link | string | 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. |
id_server | string | Required. The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification. |
Response format:
Parameter | 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 | string | 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. 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). |
Example request:
POST /_matrix/client/r0/account/password/msisdn/requestToken HTTP/1.1 Content-Type: application/json { "client_secret": "monkeys_are_GREAT", "country": "GB", "phone_number": "07700900001", "send_attempt": 1 }
Responses:
Status code 200:
An SMS message was sent to the given phone number.
Example
{ "sid": "123abc", "submit_url": "https://example.org/path/to/submitToken" }
Status code 400:
The referenced third party identifier is not recognised by the homeserver, or the request was invalid
Example
{ "errcode": "M_THREEPID_NOT_FOUND", "error": "Phone number not found" }
Status code 403:
The homeserver does not allow the third party identifier as a contact option.
Example
{ "errcode": "M_THREEPID_DENIED", "error": "Third party identifier is not allowed" }
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.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
auth | Authentication Data | Additional authentication information for the user-interactive authentication API. |
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. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The login type that the client is attempting to complete. |
session | string | The value of the session key given by the homeserver. |
Response format:
Parameter | Type | Description |
---|---|---|
id_server_unbind_result | enum | 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"] |
Example request:
POST /_matrix/client/r0/account/deactivate HTTP/1.1 Content-Type: application/json { "auth": { "type": "example.type.foo", "session": "xxxxx", "example_credential": "verypoorsharedsecret" }, "id_server": "example.org" }
Responses:
Status code 200:
The account has been deactivated.
Example
{ "id_server_unbind_result": "success" }
Status code 401:
The homeserver requires additional authentication information.
Example
{ "flows": [ { "stages": [ "example.type.foo" ] } ], "params": { "example.type.baz": { "example_key": "foobar" } }, "session": "xxxxxxyz", "completed": [ "example.type.foo" ] }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
username | string | Required. The username to check the availability of. |
Response format:
Parameter | 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. |
Example request:
GET /_matrix/client/r0/register/available?username=my_cool_localpart HTTP/1.1
Responses:
Status code 200:
The username is available
Example
{ "available": true }
Status code 400:
Part of the request was invalid or the username is not available. This may include one of the following error codes:
Example
{ "errcode": "M_USER_IN_USE", "error": "Desired user ID is already taken." }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Warning
Clients SHOULD enforce that the password provided is suitably complex. The password SHOULD include a lower-case letter, an upper-case letter, a number and a symbol and be at a minimum 8 characters in length. Servers MAY reject weak passwords with an error code M_WEAK_PASSWORD.
A homeserver may keep some contact information for administrative use. This is independent of any information kept by any identity servers.
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 auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
threepids | [Third party identifier] |
Parameter | Type | Description |
---|---|---|
medium | enum | Required. The medium of the third party identifier. One of: ["email", "msisdn"] |
address | string | Required. The third party identifier address. |
validated_at | integer | Required. The timestamp, in milliseconds, when the identifier was validated by the identity server. |
added_at | integer | Required. The timestamp, in milliseconds, when the homeserver associated the third party identifier with the user. |
Example request:
GET /_matrix/client/r0/account/3pid HTTP/1.1
Response:
Status code 200:
The lookup was successful.
Example
{ "threepids": [ { "medium": "email", "address": "monkey@banana.island", "validated_at": 1535176800000, "added_at": 1535336848756 } ] }
Adds contact information to the user's account.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
three_pid_creds | ThreePidCredentials | Required. The third party credentials to associate with the account. |
bind | boolean | Whether the homeserver should also bind this third party identifier to the account's Matrix ID with the passed identity server. Default: false. |
Parameter | Type | Description |
---|---|---|
client_secret | string | Required. The client secret used in the session with the identity server. |
id_server | string | Required. The identity server to use. |
sid | string | Required. The session identifier given by the identity server. |
Example request:
POST /_matrix/client/r0/account/3pid HTTP/1.1 Content-Type: application/json { "three_pid_creds": { "id_server": "matrix.org", "sid": "abc123987", "client_secret": "d0n'tT3ll" }, "bind": false }
Responses:
Status code 200:
The addition was successful.
Example
{ "submit_url": "https://example.org/path/to/submitToken" }
Status code 403:
The credentials could not be verified with the identity server.
Example
{ "errcode": "M_THREEPID_AUTH_FAILED", "error": "The third party credentials could not be verified by the identity server." }
Removes a third party identifier from the user's account. This might not cause an unbind of the identifier from the identity server.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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 | enum | Required. The medium of the third party identifier being removed. One of: ["email", "msisdn"] |
address | string | Required. The third party address being removed. |
Response format:
Parameter | Type | Description |
---|---|---|
id_server_unbind_result | enum | Required. An indicator as to whether or not the homeserver was able to unbind the 3PID from the identity server. success indicates that the indentity 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"] |
Example request:
POST /_matrix/client/r0/account/3pid/delete HTTP/1.1 Content-Type: application/json { "id_server": "example.org", "medium": "email", "address": "example@example.org" }
Response:
Status code 200:
The homeserver has disassociated the third party identifier from the user.
Example
{ "id_server_unbind_result": "success" }
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 has the choice of validating the email address itself, or proxying the request to the /validate/email/requestToken Identity Service API as identified by id_server. It is imperative that the homeserver keep a list of trusted Identity Servers and only proxies to those that it trusts.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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. |
string | Required. The email address to validate. | |
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. |
next_link | string | 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. |
id_server | string | Required. The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification. |
Response format:
Parameter | 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 | string | 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. 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). |
Example request:
POST /_matrix/client/r0/account/3pid/email/requestToken HTTP/1.1 Content-Type: application/json { "client_secret": "monkeys_are_GREAT", "email": "foo@example.com", "send_attempt": 1 }
Responses:
Status code 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.
Example
{ "sid": "123abc", "submit_url": "https://example.org/path/to/submitToken" }
Status code 400:
The third party identifier is already in use on the homeserver, or the request was invalid.
Example
{ "errcode": "M_THREEPID_IN_USE", "error": "Third party identifier already in use" }
Status code 403:
The homeserver does not allow the third party identifier as a contact option.
Example
{ "errcode": "M_THREEPID_DENIED", "error": "Third party identifier is not allowed" }
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 has the choice of validating the phone number itself, or proxying the request to the /validate/msisdn/requestToken Identity Service API as identified by id_server. It is imperative that the homeserver keep a list of trusted Identity Servers and only proxies to those that it trusts.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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 country code that the number in phone_number should be parsed as if it were dialled from. |
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. |
next_link | string | 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. |
id_server | string | Required. The hostname of the identity server to communicate with. May optionally include a port. This parameter is ignored when the homeserver handles 3PID verification. |
Response format:
Parameter | 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 | string | 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. 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). |
Example request:
POST /_matrix/client/r0/account/3pid/msisdn/requestToken HTTP/1.1 Content-Type: application/json { "client_secret": "monkeys_are_GREAT", "country": "GB", "phone_number": "07700900001", "send_attempt": 1 }
Responses:
Status code 200:
An SMS message was sent to the given phone number.
Example
{ "sid": "123abc", "submit_url": "https://example.org/path/to/submitToken" }
Status code 400:
The third party identifier is already in use on the homeserver, or the request was invalid.
Example
{ "errcode": "M_THREEPID_IN_USE", "error": "Third party identifier already in use" }
Status code 403:
The homeserver does not allow the third party identifier as a contact option.
Example
{ "errcode": "M_THREEPID_DENIED", "error": "Third party identifier is not allowed" }
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 auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
user_id | string | Required. The user id that owns the access token. |
Example request:
GET /_matrix/client/r0/account/whoami HTTP/1.1
Responses:
Status code 200:
The token belongs to a known user.
Example
{ "user_id": "@joe:example.org" }
Status code 401:
The token is not recognised
Example
{ "errcode": "M_UNKNOWN_TOKEN", "error": "Unrecognised access token." }
Status code 403:
The appservice cannot masquerade as the user or has not registered them.
Example
{ "errcode": "M_FORBIDDEN", "error": "Application service has not registered this user." }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
A homeserver may not support certain operations and clients must be able to query for what the homeserver can and can't offer. For example, a homeserver may not support users changing their password as it is configured to perform authentication against an external system.
The capabilities advertised through this system are intended to advertise functionality which is optional in the API, or which depend in some way on the state of the user or server. This system should not be used to advertise unstable or experimental features - this is better done by the /versions endpoint.
Some examples of what a reasonable capability could be are:
Some examples of what should not be a capability are:
Capabilities prefixed with m. are reserved for definition in the Matrix specification while other values may be used by servers using the Java package naming convention. The capabilities supported by the Matrix specification are defined later in this section.
Gets information about the server's supported feature set and other relevant capabilities.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
capabilities | Capabilities | Required. The custom capabilities the server supports, using the Java package naming convention. |
Parameter | Type | Description |
---|---|---|
m.change_password | ChangePasswordCapability | Capability to indicate if the user can change their password. |
m.room_versions | RoomVersionsCapability | The room versions the server supports. |
Parameter | Type | Description |
---|---|---|
enabled | boolean | Required. True if the user can change their password, false otherwise. |
Parameter | Type | Description |
---|---|---|
default | string | Required. The default room version the server is using for new rooms. |
available | {string: enum} | Required. A detailed description of the room versions the server supports. |
Example request:
GET /_matrix/client/r0/capabilities HTTP/1.1
Responses:
Status code 200:
The capabilities of the server.
Example
{ "capabilities": { "m.change_password": { "enabled": false }, "m.room_versions": { "default": "1", "available": { "1": "stable", "2": "stable", "3": "unstable", "test-version": "unstable" } }, "com.example.custom.ratelimit": { "max_requests_per_hour": 600 } } }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
This capability has a single flag, enabled, which indicates whether or not the user can use the /account/password API to change their password. If not present, the client should assume that password changes are possible via the API. When present, clients SHOULD respect the capability's enabled flag and indicate to the user if they are unable to change their password.
An example of the capability API's response for this capability is:
{ "capabilities": { "m.change_password": { "enabled": false } } }
This capability describes the default and available room versions a server supports, and at what level of stability. Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms.
An example of the capability API's response for this capability is:
{ "capabilities": { "m.room_versions": { "default": "1", "available": { "1": "stable", "2": "stable", "3": "unstable", "custom-version": "unstable" } } } }
This capability mirrors the same restrictions of room versions to describe which versions are stable and unstable. Clients should assume that the default version is stable. Any version not explicitly labelled as stable in the available versions is to be treated as unstable. For example, a version listed as future-stable should be treated as unstable.
The default version is the version the server is using to create new rooms. Clients should encourage users with sufficient permissions in a room to upgrade their room to the default version when the room is using an unstable version.
When this capability is not listed, clients should use "1" as the default and only stable available room version.
Note
The paths referred to in this section are not actual endpoints. They only serve as examples to explain how pagination functions.
Pagination is the process of dividing a dataset into multiple discrete pages. Matrix makes use of pagination to allow clients to view extremely large datasets. These datasets are not limited to events in a room (for example clients may want to paginate a list of rooms in addition to events within those rooms). Regardless of what is being paginated, there is a common approach which is used to give clients an easy way of selecting subsets of a potentially changing dataset. Each endpoint that uses pagination may use different parameters. However the theme among them is that they take a from and to token, and occasionally a limit and dir. Together, these parameters describe the position in a data set, where from and to are known as "stream tokens" matching the regular expression [a-zA-Z0-9.=_-]+. If supported, the dir defines the direction of events to return: either forwards (f) or backwards (b). The response may contain tokens that can be used for retrieving results before or after the returned set. These tokens may be called start or prev_batch for retrieving the previous result set, or end, next_batch or next_token for retrieving the next result set.
In the following examples, 'START' and 'END' are placeholders to signify the start and end of the data sets respectively.
For example, if an endpoint had events E1 -> E15. The client wants the last 5 events and doesn't know any previous events:
S E |-E1-E2-E3-E4-E5-E6-E7-E8-E9-E10-E11-E12-E13-E14-E15-| | | | | _____| <--backwards-- | |__________________ | | ________| | | | | GET /somepath?to=START&limit=5&dir=b&from=END Returns: E15,E14,E13,E12,E11
Another example: a public room list has rooms R1 -> R17. The client is showing 5 rooms at a time on screen, and is on page 2. They want to now show page 3 (rooms R11 -> 15):
S E | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | stream token |-R1-R2-R3-R4-R5-R6-R7-R8-R9-R10-R11-R12-R13-R14-R15-R16-R17| room |____________| |________________| | | Currently | viewing | | GET /roomslist?from=9&to=END&limit=5 Returns: R11,R12,R13,R14,R15
Note that tokens are treated in an exclusive, not inclusive, manner. The end token from the initial request was '9' which corresponded to R10. When the 2nd request was made, R10 did not appear again, even though from=9 was specified. If you know the token, you already have the data.
Responses for pagination-capable endpoints SHOULD have a chunk array alongside the applicable stream tokens to represent the result set.
In general, when the end of a result set is reached the applicable stream token will be excluded from the response. For example, if a user was backwards-paginating events in a room they'd eventually reach the first event in the room. In this scenario, the prev_batch token would be excluded from the response. Some paginated endpoints are open-ended in one direction, such as endpoints which expose an event stream for an active room. In this case, it is not possible for the client to reach the true "end" of the data set and therefore should always be presented with a token to keep moving forwards.
Filters can be created on the server and can be passed as as a parameter to APIs which return events. These filters alter the data returned from those APIs. Not all APIs accept filters.
Membership events often take significant resources for clients to track. In an effort to reduce the number of resources used, clients can enable "lazy-loading" for room members. By doing this, servers will attempt to only send membership events which are relevant to the client.
It is important to understand that lazy-loading is not intended to be a perfect optimisation, and that it may not be practical for the server to calculate precisely which membership events are relevant to the client. As a result, it is valid for the server to send redundant membership events to the client to ease implementation, although such redundancy should be minimised where possible to conserve bandwidth.
In terms of filters, lazy-loading is enabled by enabling lazy_load_members on a RoomEventFilter (or a StateFilter in the case of /sync only). When enabled, lazy-loading aware endpoints (see below) will only include membership events for the sender of events being included in the response. For example, if a client makes a /sync request with lazy-loading enabled, the server will only return membership events for the sender of events in the timeline, not all members of a room.
When processing a sequence of events (e.g. by looping on /sync or paginating /messages), it is common for blocks of events in the sequence to share a similar set of senders. Rather than responses in the sequence sending duplicate membership events for these senders to the client, the server MAY assume that clients will remember membership events they have already been sent, and choose to skip sending membership events for members whose membership has not changed. These are called 'redundant membership events'. Clients may request that redundant membership events are always included in responses by setting include_redundant_members to true in the filter.
The expected pattern for using lazy-loading is currently:
The current endpoints which support lazy-loading room members are:
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The id of the user uploading the filter. The access token must be authorized to make requests for this user id. |
JSON body parameters | ||
event_fields | [string] | List of event fields to include. If this list is absent then all fields are included. The entries may include '.' charaters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\'. A server may include more fields than were requested. |
event_format | enum | The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as receieved over federation. The default is 'client'. One of: ["client", "federation"] |
presence | EventFilter | The presence updates to include. |
account_data | EventFilter | The user account data that isn't associated with rooms to include. |
room | RoomFilter | Filters to be applied to room data. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
Parameter | Type | Description |
---|---|---|
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 |
ephemeral | RoomEventFilter | The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms. |
include_leave | boolean | Include rooms that the user has left in the sync, default false |
state | StateFilter | The state events to include for rooms. |
timeline | RoomEventFilter | The message and state update events to include for rooms. |
account_data | RoomEventFilter | The per user account data to include for rooms. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
lazy_load_members | boolean | If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false. |
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. |
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. |
rooms | [string] | A list of room IDs to include. If this list is absent then all rooms are included. |
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. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
lazy_load_members | boolean | If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false. |
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. |
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. |
rooms | [string] | A list of room IDs to include. If this list is absent then all rooms are included. |
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. |
Response format:
Parameter | 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. |
Example request:
POST /_matrix/client/r0/user/%40alice%3Aexample.com/filter HTTP/1.1 Content-Type: application/json { "room": { "state": { "types": [ "m.room.*" ], "not_rooms": [ "!726s6s6q:example.com" ] }, "timeline": { "limit": 10, "types": [ "m.room.message" ], "not_rooms": [ "!726s6s6q:example.com" ], "not_senders": [ "@spam:example.com" ] }, "ephemeral": { "types": [ "m.receipt", "m.typing" ], "not_rooms": [ "!726s6s6q:example.com" ], "not_senders": [ "@spam:example.com" ] } }, "presence": { "types": [ "m.presence" ], "not_senders": [ "@alice:example.com" ] }, "event_format": "client", "event_fields": [ "type", "content", "sender" ] }
Response:
Status code 200:
The filter was created.
Example
{ "filter_id": "66696p746572" }
Download a filter
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user ID to download a filter for. |
filterId | string | Required. The filter ID to download. |
Response format:
Parameter | Type | Description |
---|---|---|
event_fields | [string] | List of event fields to include. If this list is absent then all fields are included. The entries may include '.' charaters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\'. A server may include more fields than were requested. |
event_format | enum | The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as receieved over federation. The default is 'client'. One of: ["client", "federation"] |
presence | EventFilter | The presence updates to include. |
account_data | EventFilter | The user account data that isn't associated with rooms to include. |
room | RoomFilter | Filters to be applied to room data. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
Parameter | Type | Description |
---|---|---|
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 |
ephemeral | RoomEventFilter | The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms. |
include_leave | boolean | Include rooms that the user has left in the sync, default false |
state | StateFilter | The state events to include for rooms. |
timeline | RoomEventFilter | The message and state update events to include for rooms. |
account_data | RoomEventFilter | The per user account data to include for rooms. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
lazy_load_members | boolean | If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false. |
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. |
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. |
rooms | [string] | A list of room IDs to include. If this list is absent then all rooms are included. |
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. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
lazy_load_members | boolean | If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false. |
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. |
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. |
rooms | [string] | A list of room IDs to include. If this list is absent then all rooms are included. |
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. |
Example request:
GET /_matrix/client/r0/user/%40alice%3Aexample.com/filter/66696p746572 HTTP/1.1
Responses:
Status code 200:
"The filter defintion"
Example
{ "room": { "state": { "types": [ "m.room.*" ], "not_rooms": [ "!726s6s6q:example.com" ] }, "timeline": { "limit": 10, "types": [ "m.room.message" ], "not_rooms": [ "!726s6s6q:example.com" ], "not_senders": [ "@spam:example.com" ] }, "ephemeral": { "types": [ "m.receipt", "m.typing" ], "not_rooms": [ "!726s6s6q:example.com" ], "not_senders": [ "@spam:example.com" ] } }, "presence": { "types": [ "m.presence" ], "not_senders": [ "@alice:example.com" ] }, "event_format": "client", "event_fields": [ "type", "content", "sender" ] }
Status code 404:
Unknown filter.
The model of conversation history exposed by the client-server API can be considered as a list of events. The server 'linearises' the eventually-consistent event graph of events into an 'event stream' at any given point in time:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]
Warning
The format of events can change depending on room version. Check the room version specification for specific details on what to expect for event formats. Examples contained within the client-server specification are expected to be compatible with all specified room versions, however some differences may still apply.
For this version of the specification, clients only need to worry about the event ID format being different depending on room version. Clients should not be parsing the event ID, and instead be treating it as an opaque string. No changes should be required to support the currently available room versions.
Room events are split into two categories:
State Events: | These are events which update the metadata state of the room (e.g. room topic, room membership etc). State is keyed by a tuple of event type and a state_key. State in the room with the same key-tuple will be overwritten. |
---|---|
Message events: | These are events which describe transient "once-off" activity in a room: typically communication such as sending an instant message or setting up a VoIP call. |
This specification outlines several events, all with the event type prefix m.. (See Room Events for the m. event specification.) However, applications may wish to add their own type of event, and this can be achieved using the REST API detailed in the following sections. If new events are added, the event type key SHOULD follow the Java package naming convention, e.g. com.example.myapp.event. This ensures event types are suitably namespaced for each application and reduces the risk of clashes.
Note
Events are not limited to the types defined in this specification. New or custom event types can be created on a whim using the Java package naming convention. For example, a com.example.game.score event can be sent by clients and other clients would receive it through Matrix, assuming the client has access to the com.example namespace.
Note that the structure of these events may be different than those in the server-server API.
The basic set of fields all events must have.
Key | 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' |
Room Events have the following fields.
Key | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Key | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
In addition to the fields of a Room Event, State Events have the following fields.
Key | Type | Description |
---|---|---|
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
The complete event MUST NOT be larger than 65535 bytes, when formatted as a PDU for the Server-Server protocol, including any signatures, and encoded as Canonical JSON.
There are additional restrictions on sizes per key:
Some event types have additional size restrictions which are specified in the description of the event. Additional keys have no limit other than that implied by the total 65 KB limit on events.
Note
This section is a work in progress.
This specification outlines several standard event types, all of which are prefixed with m.
This event is sent by a homeserver directly to inform of changes to the list of aliases it knows about for that room. The state_key for this event is set to the homeserver which owns the room alias. The entire set of known aliases for the room is the union of all the m.room.aliases events, one for each homeserver. Clients should check the validity of any room alias given in this list before presenting it to the user as trusted fact. The lists given by this event should be considered simply as advice on which aliases might exist, for which the client can perform the lookup to confirm whether it receives the correct room ID.
Content Key | Type | Description |
---|---|---|
aliases | [string] | Required. A list of room aliases. |
Example:
{ "content": { "aliases": [ "#somewhere:example.org", "#another:example.org" ] }, "event_id": "$143273582443PhrSn:example.org", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "state_key": "example.org", "type": "m.room.aliases", "unsigned": { "age": 1234 } }
This event is used to inform the room about which alias should be considered the canonical one. This could be for display purposes or as suggestion to users which alias to use to advertise the room.
A room with an m.room.canonical_alias event with an absent, null, or empty alias field should be treated the same as a room with no m.room.canonical_alias event.
Content Key | Type | Description |
---|---|---|
alias | string | Required. The canonical alias. |
Example:
{ "content": { "alias": "#somewhere:localhost" }, "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 } }
This is the first event in a room and cannot be changed. It acts as the root of all other events.
Content Key | Type | Description |
---|---|---|
creator | string | Required. The user_id of the room creator. This is set by the homeserver. |
m.federate | boolean | Whether users on other servers can join this room. Defaults to true if key does not exist. |
room_version | string | The version of the room. Defaults to "1" if the key does not exist. |
predecessor | Previous Room | A reference to the room this room replaces, if the previous room was upgraded. |
Previous Room Key | Type | Description |
---|---|---|
room_id | string | Required. The ID of the old room. |
event_id | string | Required. The event ID of the last known event in the old room. |
Example:
{ "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", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "state_key": "", "type": "m.room.create", "unsigned": { "age": 1234 } }
A room may be public meaning anyone can join the room without any prior action. Alternatively, it can be invite meaning that a user who wishes to join the room must first receive an invite to the room from someone already inside of the room. Currently, knock and private are reserved keywords which are not implemented.
Content Key | Type | Description |
---|---|---|
join_rule | enum | Required. The type of rules used for users wishing to join this room. One of: ["public", "knock", "invite", "private"] |
Example:
{ "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 } }
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:
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 StrippedState Events. These events provide information on a subset of state events such as the room name.
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. | Not implemented. |
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. | Not implemented. |
from leave | New invitation sent. | User joined. | No change. | User was banned. | Not implemented. |
from ban | Must never happen. | Must never happen. | User was unbanned. | No change. | Not implemented. |
from knock | Not implemented. | Not implemented. | Not implemented. | Not implemented. | Not implemented. |
EventContent Key | Type | Description |
---|---|---|
avatar_url | string | The avatar URL for this user, if any. This is added by the homeserver. |
displayname | string or null | The display name for this user, if any. This is added by the homeserver. |
membership | enum | Required. The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] |
is_direct | boolean | Flag indicating if the room containing this event was created with the intention of being a direct chat. See Direct Messaging. |
third_party_invite | Invite | |
unsigned | UnsignedData | Contains optional extra information about the event. |
Invite Key | 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 Key | Type | Description |
---|---|---|
mxid | string | Required. The invited matrix user ID. Must be equal to the user_id property of the event. |
signatures | Signatures | 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. |
UnsignedData Key | Type | Description |
---|---|---|
invite_room_state | [StrippedState] | A subset of the state of the room at the time of the invite, if membership is invite. Note that this state is informational, and SHOULD NOT be trusted; once the client has joined the room, it SHOULD fetch the live state from the server and discard the invite_room_state. Also, clients must not rely on any particular state being present here; they SHOULD behave properly (with possibly a degraded but not a broken experience) in the absence of any particular events here. If they are set on the room, at least the state for m.room.avatar, m.room.canonical_alias, m.room.join_rules, and m.room.name SHOULD be included. |
StrippedState Key | Type | Description |
---|---|---|
content | EventContent | Required. The content for the event. |
state_key | string | Required. The state_key for the event. |
type | string | Required. The type for the event. |
sender | string | Required. The sender for the event. |
Examples:
{ "content": { "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid", "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": "invite" }, "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", "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 } }
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, the state_default is 50. If there is no events_default in the m.room.power_levels event, the events_default is 0. If the room contains no m.room.power_levels event, both the state_default and events_default are 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, is defined by invite, kick, ban, and redact, respectively. Each of these levels defaults 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.
Note
As noted above, in the absence of an m.room.power_levels event, the state_default is 0, and all users are considered to have power level 0. That means that any member of the room can send an m.room.power_levels event, changing the permissions in the room.
Server implementations should therefore ensure that each room has an m.room.power_levels event as soon as it is created. See also the documentation of the /createRoom API.
Content Key | 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 50 if unspecified. |
kick | integer | The level required to kick a user. Defaults to 50 if unspecified. |
redact | integer | The level required to redact an event. 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 | {string: integer} | The power levels for specific users. This is a mapping from user_id to power level for that user. |
users_default | integer | The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 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. |
Notifications Key | Type | Description |
---|---|---|
room | integer | The level required to trigger an @room notification. Defaults to 50 if unspecified. |
Example:
{ "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 } }
Message Event
Events can be redacted by either room or server admins. Redacting an event means that all keys not required by the protocol are stripped off, allowing admins to remove offensive or illegal content that may have been attached to any event. This cannot be undone, allowing server owners to physically delete the offending data. There is also a concept of a moderator hiding a message event, which can be undone, but cannot be applied to state events. The event that has been redacted is specified in the redacts event level key.
Content Key | Type | Description |
---|---|---|
reason | string | The reason for the redaction, if any. |
Example:
{ "content": { "reason": "Spamming" }, "event_id": "$143273582443PhrSn:example.org", "origin_server_ts": 1432735824653, "redacts": "$fukweghifu23:localhost", "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "type": "m.room.redaction", "unsigned": { "age": 1234 } }
To read events, the intended flow of operation is for clients to first call the /sync API without a since parameter. This returns the most recent message events for each room, as well as the state of the room at the start of the returned timeline. The response also includes a next_batch field, which should be used as the value of the since parameter in the next call to /sync. Finally, the response includes, for each room, a prev_batch field, which can be passed as a start parameter to the /rooms/<room_id>/messages API to retrieve earlier messages.
You can visualise the range of events being returned as:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5] ^ ^ | | prev_batch: '1-2-3' next_batch: 'a-b-c'
Clients then receive new events by "long-polling" the homeserver via the /sync API, passing the value of the next_batch field from the response to the previous call as the since parameter. The client should also pass a timeout parameter. The server will then hold open the HTTP connection for a short period of time waiting for new events, returning early if an event occurs. Only the /sync API (and the deprecated /events API) support long-polling in this way.
The response for such an incremental sync can be visualised as:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6] ^ ^ | | | next_batch: 'x-y-z' prev_batch: 'a-b-c'
Normally, all new events which are visible to the client will appear in the response to the /sync API. However, if a large number of events arrive between calls to /sync, a "limited" timeline is returned, containing only the most recent message events. A state "delta" is also returned, summarising any state changes in the omitted part of the timeline. The client may therefore end up with "gaps" in its knowledge of the message timeline. The client can fill these gaps using the /rooms/<room_id>/messages API. This situation looks like this:
| gap | | <-> | [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10] ^ ^ | | prev_batch: 'd-e-f' next_batch: 'u-v-w'
Warning
Events are ordered in this API according to the arrival time of the event on the homeserver. This can conflict with other APIs which order events based on their partial ordering in the event graph. This can result in duplicate events being received (once per distinct API called). Clients SHOULD de-duplicate events based on the event ID when this happens.
Note
The /sync API returns a state list which is separate from the timeline. This state list allows clients to keep their model of the room state in sync with that on the server. In the case of an initial (since-less) sync, the state list represents the complete state of the room at the start of the returned timeline (so in the case of a recently-created room whose state fits entirely in the timeline, the state list will be empty).
In the case of an incremental sync, the state list gives a delta between the state of the room at the since parameter and that at the start of the returned timeline. (It will therefore be empty unless the timeline was limited.)
In both cases, it should be noted that the events returned in the state list did not necessarily take place just before the returned timeline, so clients should not display them to the user in the timeline.
Rationale
An early design of this specification made the state list represent the room state at the end of the returned timeline, instead of the start. This was unsatisfactory because it led to duplication of events between the state list and the timeline, but more importantly, it made it difficult for clients to show the timeline correctly.
In particular, consider a returned timeline [M0, S1, M2], where M0 and M2 are both messages sent by the same user, and S1 is a state event where that user changes their displayname. If the state list represents the room state at the end of the timeline, the client must take a copy of the state dictionary, and rewind S1, in order to correctly calculate the display name for M0.
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 a StateFilter 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.
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.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
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. |
since | string | A point in time to continue a sync from. |
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 | enum | 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"] |
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. |
Response format:
Parameter | Type | Description |
---|---|---|
next_batch | string | Required. The batch token to supply in the since param of the next /sync request. |
rooms | Rooms | Updates to rooms. |
presence | Presence | The updates to the presence status of other users. |
account_data | Account Data | The global private data created by this user. |
to_device | ToDevice | Information on the send-to-device messages for the client device, as defined in Send-to-Device messaging. |
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. |
Parameter | Type | Description |
---|---|---|
join | {string: Joined Room} | The rooms that the user has joined. |
invite | {string: Invited Room} | The rooms that the user has been invited to. |
leave | {string: Left Room} | The rooms that the user has left or been banned from. |
Parameter | Type | Description |
---|---|---|
summary | RoomSummary | Information about the room which clients may need to correctly render it to users. |
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. |
timeline | Timeline | The timeline of messages and state changes in the room. |
ephemeral | Ephemeral | The ephemeral events in the room that aren't recorded in the timeline or state of the room. e.g. typing. |
account_data | Account Data | The private data that this user has attached to this 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. |
Parameter | 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.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. |
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. |
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events. |
Parameter | 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 |
Parameter | Type | Description |
---|---|---|
invite_state | InviteState | The state of a room that the user has been invited to. These state events may only have the sender, type, state_key and content keys present. These events do not replace any state that the client already has for the room, for example if the client has archived the room. Instead the client should keep two separate copies of the state: the one from the invite_state and one from the archived state. If the client joins the room then the current state will be given as a delta against the archived state not the invite_state. |
Parameter | Type | Description |
---|---|---|
events | [StrippedState] | The StrippedState events that form the invite state. |
Parameter | Type | Description |
---|---|---|
content | EventContent | Required. The content for the event. |
state_key | string | Required. The state_key for the event. |
type | string | Required. The type for the event. |
sender | string | Required. The sender for the event. |
Parameter | Type | Description |
---|---|---|
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 | Account Data | The private data that this user has attached to this room. |
Parameter | Type | Description |
---|---|---|
events | [State Event] | List of events. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | Type | Description |
---|---|---|
events | [Room Event] | 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/{roomId}/messages endpoint. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events. |
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events. |
Parameter | 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' |
Example request:
GET /_matrix/client/r0/sync?filter=66696p746572&since=s72594_4483_1934&full_state=false&set_presence=offline&timeout=30000 HTTP/1.1
Response:
Status code 200:
The initial snapshot or delta for the client to use to update their state.
Example
{ "next_batch": "s72595_4483_1934", "presence": { "events": [ { "content": { "avatar_url": "mxc://localhost:wefuiwegh8742w", "last_active_ago": 2478593, "presence": "online", "currently_active": false, "status_msg": "Making cupcakes" }, "type": "m.presence", "sender": "@example:localhost" } ] }, "account_data": { "events": [ { "type": "org.example.custom.config", "content": { "custom_config_key": "custom_config_value" } } ] }, "rooms": { "join": { "!726s6s6q:example.com": { "summary": { "m.heroes": [ "@alice:example.com", "@bob:example.com" ], "m.joined_member_count": 2, "m.invited_member_count": 0 }, "state": { "events": [ { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!726s6s6q:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" } ] }, "timeline": { "events": [ { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!726s6s6q:example.com", "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": "!726s6s6q:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ], "limited": true, "prev_batch": "t34-23535_0_0" }, "ephemeral": { "events": [ { "content": { "user_ids": [ "@alice:matrix.org", "@bob:example.com" ] }, "type": "m.typing", "room_id": "!jEsUZKDJdhlrceRyVU:example.org" } ] }, "account_data": { "events": [ { "content": { "tags": { "u.work": { "order": 0.9 } } }, "type": "m.tag" }, { "type": "org.example.custom.room.config", "content": { "custom_config_key": "custom_config_value" } } ] } } }, "invite": { "!696r7674:example.com": { "invite_state": { "events": [ { "sender": "@alice:example.com", "type": "m.room.name", "state_key": "", "content": { "name": "My Room Name" } }, { "sender": "@alice:example.com", "type": "m.room.member", "state_key": "@bob:example.com", "content": { "membership": "invite" } } ] } } }, "leave": {} } }
Warning
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 API with a since parameter. See the migration guide.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
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. |
Response format:
Parameter | Type | Description |
---|---|---|
start | string | A token which correlates to the first value in chunk. This is usually the same token supplied to from=. |
end | string | A token which correlates to the last value in chunk. This token should be used in the next request to /events. |
chunk | [Event] | An array of events. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
GET /_matrix/client/r0/events?from=s3456_9_0&timeout=35000 HTTP/1.1
Responses:
Status code 200:
The events received, which may be none.
Example
{ "start": "s3456_9_0", "end": "s3457_9_0", "chunk": [ { "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 } } ] }
Status code 400:
Bad pagination from parameter.
Warning
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 API with no since parameter. See the migration guide.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
limit | integer | The maximum number of messages to return for each room. |
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. |
Response format:
Parameter | Type | Description |
---|---|---|
end | string | Required. A token which correlates to the last value in chunk. This token should be used with the /events API to listen for new events. |
presence | [Event] | Required. A list of presence events. |
rooms | [RoomInfo] | Required. |
account_data | [Event] | The global private data created by this user. |
Parameter | Type | Description |
---|---|---|
room_id | string | Required. The ID of this room. |
membership | enum | Required. The user's membership state in this room. One of: ["invite", "join", "leave", "ban"] |
invite | InviteEvent | The invite event if membership is invite |
messages | PaginationChunk | The pagination chunk for this room. |
state | [StateEvent] | 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 | enum | Whether this room is visible to the /publicRooms API or not." One of: ["private", "public"] |
account_data | [Event] | The private data that this user has attached to this room. |
Parameter | Type | Description |
---|---|---|
content | EventContent | Required. |
type | string | Required. Must be 'm.room.member'. |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. 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. |
Parameter | Type | Description |
---|---|---|
avatar_url | string | The avatar URL for this user, if any. This is added by the homeserver. |
displayname | string or null | The display name for this user, if any. This is added by the homeserver. |
membership | enum | Required. The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] |
is_direct | boolean | Flag indicating if the room containing this event was created with the intention of being a direct chat. See Direct Messaging. |
third_party_invite | Invite | |
unsigned | UnsignedData | Contains optional extra information about the event. |
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
mxid | string | Required. The invited matrix user ID. Must be equal to the user_id property of the event. |
signatures | Signatures | 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. |
Parameter | Type | Description |
---|---|---|
content | EventContent | Required. The content for the event. |
state_key | string | Required. The state_key for the event. |
type | string | Required. The type for the event. |
sender | string | Required. The sender for the event. |
Parameter | Type | Description |
---|---|---|
start | string | Required. A token which correlates to the first value in chunk. Used for pagination. |
end | string | Required. A token which correlates to the last value in chunk. Used for pagination. |
chunk | [RoomEvent] | 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 preceeded them leaving. This array will consist of at most limit elements. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Parameter | 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' |
Example request:
GET /_matrix/client/r0/initialSync?limit=2&archived=true HTTP/1.1
Responses:
Status code 200:
The user's current state.
Example
{ "end": "s3456_9_0", "presence": [ { "content": { "avatar_url": "mxc://localhost:wefuiwegh8742w", "last_active_ago": 2478593, "presence": "online", "currently_active": false, "status_msg": "Making cupcakes" }, "type": "m.presence", "sender": "@example:localhost" } ], "account_data": [ { "type": "org.example.custom.config", "content": { "custom_config_key": "custom_config_value" } } ], "rooms": [ { "membership": "join", "messages": { "chunk": [ { "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": "!TmaZBKYIFrIPVGoUYp:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } }, { "content": { "body": "Gangnam Style", "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442", "info": { "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe", "thumbnail_info": { "mimetype": "image/jpeg", "size": 46144, "w": 300, "h": 300 }, "w": 480, "h": 320, "duration": 2140786, "size": 1563685, "mimetype": "video/mp4" }, "msgtype": "m.video" }, "type": "m.room.message", "event_id": "$143273582443PhrSn:example.org", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ], "end": "s3456_9_0", "start": "t44-3453_9_0" }, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state": [ { "content": { "join_rule": "public" }, "type": "m.room.join_rules", "event_id": "$143273582443PhrSn:example.org", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" }, { "content": { "creator": "@example:example.org", "room_version": "1", "m.federate": true, "predecessor": { "event_id": "$something:example.org", "room_id": "!oldroom:example.org" } }, "type": "m.room.create", "event_id": "$143273582443PhrSn:example.org", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "invite": 50, "kick": 50, "redact": 50, "state_default": 50, "users": { "@example:localhost": 100 }, "users_default": 0, "notifications": { "room": 20 } }, "type": "m.room.power_levels", "event_id": "$143273582443PhrSn:example.org", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" } ], "visibility": "private", "account_data": [ { "type": "m.tag", "content": { "tags": { "work": { "order": 1 } } } }, { "type": "org.example.custom.room.config", "content": { "custom_config_key": "custom_config_value" } } ] } ] }
Status code 404:
There is no avatar URL for this user or this user does not exist.
Warning
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
eventId | string | Required. The event ID to get. |
Response format:
Parameter | 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' |
Example request:
GET /_matrix/client/r0/events/%24asfDuShaf7Gafaw%3Amatrix.org HTTP/1.1
Responses:
Status code 200:
The full event.
Example
{ "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 } }
Status code 404:
The event was not found or you do not have permission to read this event.
There are several APIs provided to GET events for a room:
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The ID of the room the event is in. |
eventId | string | Required. The event ID to get. |
Response format:
Parameter | 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' |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Amatrix.org/event/%24asfDuShaf7Gafaw%3Amatrix.org HTTP/1.1
Responses:
Status code 200:
The full event.
Example
{ "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": "!636q39766251:matrix.org", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } }
Status code 404:
The event was not found or you do not have permission to read this event.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to look up the state in. |
eventType | string | Required. The type of state to look up. |
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. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/state/m.room.name/ HTTP/1.1
Responses:
Status code 200:
The content of the state event.
Example
{ "name": "Example room name" }
Status code 403:
You aren't a member of the room and weren't previously a member of the room.
Status code 404:
The room has no state with the given type or key.
Get the state events for the current state of a room.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to look up the state for. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | [StateEvent] | 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 then this will be the state of the room when they left as a list of events. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/state HTTP/1.1
Responses:
Status code 200:
The current state of the room
Example
[ { "content": { "join_rule": "public" }, "type": "m.room.join_rules", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" }, { "content": { "creator": "@example:example.org", "room_version": "1", "m.federate": true, "predecessor": { "event_id": "$something:example.org", "room_id": "!oldroom:example.org" } }, "type": "m.room.create", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "invite": 50, "kick": 50, "redact": 50, "state_default": 50, "users": { "@example:localhost": 100 }, "users_default": 0, "notifications": { "room": 20 } }, "type": "m.room.power_levels", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" } ]
Status code 403:
You aren't a member of the room and weren't previously a member of the room.
Get the list of members for this room.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get the member events for. |
query parameters | ||
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 | enum | 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", "leave", "ban"] |
not_membership | enum | The kind of membership to exclude from the results. Defaults to no filtering if unspecified. One of: ["join", "invite", "leave", "ban"] |
Response format:
Parameter | Type | Description |
---|---|---|
chunk | [MemberEvent] |
Parameter | Type | Description |
---|---|---|
content | EventContent | Required. |
type | string | Required. Must be 'm.room.member'. |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. 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. |
Parameter | Type | Description |
---|---|---|
avatar_url | string | The avatar URL for this user, if any. This is added by the homeserver. |
displayname | string or null | The display name for this user, if any. This is added by the homeserver. |
membership | enum | Required. The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] |
is_direct | boolean | Flag indicating if the room containing this event was created with the intention of being a direct chat. See Direct Messaging. |
third_party_invite | Invite | |
unsigned | UnsignedData | Contains optional extra information about the event. |
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
mxid | string | Required. The invited matrix user ID. Must be equal to the user_id property of the event. |
signatures | Signatures | 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. |
Parameter | Type | Description |
---|---|---|
content | EventContent | Required. The content for the event. |
state_key | string | Required. The state_key for the event. |
type | string | Required. The type for the event. |
sender | string | Required. The sender for the event. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/members?at=YWxsCgpOb25lLDM1ODcwOA&membership=join¬_membership=leave HTTP/1.1
Responses:
Status code 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.
Example
{ "chunk": [ { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" } ] }
Status code 403:
You aren't a member of the room and weren't previously a member of the room.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get the members of. |
Response format:
Parameter | Type | Description |
---|---|---|
joined | {string: RoomMember} | A map from user ID to a RoomMember object. |
Parameter | Type | Description |
---|---|---|
display_name | string | The display name of the user this object is representing. |
avatar_url | string | The mxc avatar url of the user this object is representing. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/joined_members HTTP/1.1
Responses:
Status code 200:
A map of MXID to room member objects.
Example
{ "joined": { "@bar:example.com": { "display_name": "Bar", "avatar_url": "mxc://riot.ovh/printErCATzZijQsSDWorRaK" } } }
Status code 403:
You aren't a member of the room.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get events from. |
query parameters | ||
from | string | Required. The token to start returning events from. This token can be obtained from a prev_batch token returned for each room by the sync API, or from a start or end token returned by a previous request to this endpoint. |
to | string | The token to stop returning events at. This token can be obtained from a prev_batch token returned for each room by the sync endpoint, or from a start or end token returned by a previous request to this endpoint. |
dir | enum | Required. The direction to return events from. One of: ["b", "f"] |
limit | integer | The maximum number of events to return. Default: 10. |
filter | string | A JSON RoomEventFilter to filter returned events with. |
Response format:
Parameter | Type | Description |
---|---|---|
start | string | The token the pagination starts from. If dir=b this will be the token supplied in from. |
end | string | The token the pagination ends at. If dir=b this token should be used again to request even earlier events. |
chunk | [RoomEvent] | 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, so that events start at the from point. |
state | [RoomStateEvent] | 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. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/messages?from=s345_678_333&dir=b&limit=3&filter=%7B%22contains_url%22%3Atrue%7D HTTP/1.1
Responses:
Status code 200:
A list of messages with a new token to request more.
Example
{ "start": "t47429-4392820_219380_26003_2265", "end": "t47409-4357353_219380_26003_2265", "chunk": [ { "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": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } }, { "content": { "name": "The room name" }, "type": "m.room.name", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "body": "Gangnam Style", "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442", "info": { "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe", "thumbnail_info": { "mimetype": "image/jpeg", "size": 46144, "w": 300, "h": 300 }, "w": 480, "h": 320, "duration": 2140786, "size": 1563685, "mimetype": "video/mp4" }, "msgtype": "m.video" }, "type": "m.room.message", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ] }
Status code 403:
You aren't a member of the room.
Warning
This API is deprecated and will be removed from a future release.
Get a copy of the current state and the most recent messages in a room.
This endpoint was deprecated in r0 of this specification. There is no direct replacement; the relevant information is returned by the /sync API. See the migration guide.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get the data. |
Response format:
Parameter | Type | Description |
---|---|---|
room_id | string | Required. The ID of this room. |
membership | enum | The user's membership state in this room. One of: ["invite", "join", "leave", "ban"] |
messages | PaginationChunk | The pagination chunk for this room. |
state | [StateEvent] | 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 | enum | Whether this room is visible to the /publicRooms API or not." One of: ["private", "public"] |
account_data | [Event] | The private data that this user has attached to this room. |
Parameter | Type | Description |
---|---|---|
start | string | Required. A token which correlates to the first value in chunk. Used for pagination. |
end | string | Required. A token which correlates to the last value in chunk. Used for pagination. |
chunk | [RoomEvent] | 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 preceeded them leaving. This array will consist of at most limit elements. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Parameter | 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' |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/initialSync HTTP/1.1
Responses:
Status code 200:
The current state of the room
Example
{ "membership": "join", "messages": { "chunk": [ { "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": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } }, { "content": { "body": "something-important.doc", "filename": "something-important.doc", "info": { "mimetype": "application/msword", "size": 46144 }, "msgtype": "m.file", "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe" }, "type": "m.room.message", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ], "end": "s3456_9_0", "start": "t44-3453_9_0" }, "room_id": "!636q39766251:example.com", "state": [ { "content": { "join_rule": "public" }, "type": "m.room.join_rules", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" }, { "content": { "creator": "@example:example.org", "room_version": "1", "m.federate": true, "predecessor": { "event_id": "$something:example.org", "room_id": "!oldroom:example.org" } }, "type": "m.room.create", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "invite": 50, "kick": 50, "redact": 50, "state_default": 50, "users": { "@example:localhost": 100 }, "users_default": 0, "notifications": { "room": 20 } }, "type": "m.room.power_levels", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" } ], "visibility": "private", "account_data": [ { "type": "m.tag", "content": { "tags": { "work": { "order": "1" } } } } ] }
Status code 403:
You aren't a member of the room and weren't previously a member of the room.
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.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to set the state in |
eventType | string | Required. The type of event to send. |
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. |
Response format:
Parameter | Type | Description |
---|---|---|
event_id | string | A unique identifier for the event. |
Example request:
PUT /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/state/m.room.member/%40alice%3Aexample.com HTTP/1.1 Content-Type: application/json { "membership": "join", "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }
Responses:
Status code 200:
An ID for the sent event.
Example
{ "event_id": "$YUwRidLecu:example.com" }
Status code 403:
The sender doesn't have permission to send the event into the room.
Example
{ "errcode": "M_FORBIDDEN", "error": "You do not have permission to send the event." }
Examples
Valid requests look like:
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" }
In contrast, these requests are invalid:
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" }
Care should be taken to avoid setting the wrong state key:
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" }
The state_key is often used to store state about individual users, by using the user ID as the state_key value. For example:
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org { "animal" : "cat", "reason": "fluffy" }
In some cases, there may be no need for a state_key, so it can be omitted:
PUT /rooms/!roomid:domain/state/m.room.bgd.color { "color": "red", "hex": "#ff0000" }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to send the event to. |
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. |
Response format:
Parameter | Type | Description |
---|---|---|
event_id | string | A unique identifier for the event. |
Example request:
PUT /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/send/m.room.message/35 HTTP/1.1 Content-Type: application/json { "msgtype": "m.text", "body": "hello" }
Response:
Status code 200:
An ID for the sent event.
Example
{ "event_id": "$YUwRidLecu:example.com" }
Since events are extensible it is possible for malicious users and/or servers to add keys that are, for example offensive or illegal. Since some events cannot be simply deleted, e.g. membership events, we instead 'redact' events. This involves removing all keys from an event that are not required by the protocol. This stripped down event is thereafter returned anytime a client or remote server requests it. Redacting an event cannot be undone, allowing server owners to delete the offending content from the databases. Events that have been redacted include a redacted_because key whose value is the event that caused it to be redacted, which may include a reason.
Upon receipt of a redaction event, the server should strip off any keys not in the following list:
The content object should also be stripped of all keys, unless it is one of one of the following event types:
The server should add the event causing the redaction to the unsigned property of the redacted event, under the redacted_because key. When a client receives a redaction event it should change the redacted event in the same way a server does.
Note
Redacted events can still affect the state of the room. When redacted, state events behave as though their properties were simply not specified, except those protected by the redaction algorithm. For example, a redacted join event will still result in the user being considered joined. Similarly, a redacted topic does not necessarily cause the topic to revert to what is was prior to the event - it causes the topic to be removed from the room.
Message Event
Events can be redacted by either room or server admins. Redacting an event means that all keys not required by the protocol are stripped off, allowing admins to remove offensive or illegal content that may have been attached to any event. This cannot be undone, allowing server owners to physically delete the offending data. There is also a concept of a moderator hiding a message event, which can be undone, but cannot be applied to state events. The event that has been redacted is specified in the redacts event level key.
Content Key | Type | Description |
---|---|---|
reason | string | The reason for the redaction, if any. |
Example:
{ "content": { "reason": "Spamming" }, "event_id": "$143273582443PhrSn:example.org", "origin_server_ts": 1432735824653, "redacts": "$fukweghifu23:localhost", "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "type": "m.room.redaction", "unsigned": { "age": 1234 } }
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.
Users may redact their own events, and any user with a power level greater than or equal to the redact power level of the room may redact events there.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room from which to redact the event. |
eventId | string | Required. The ID of the event to redact |
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. |
JSON body parameters | ||
reason | string | The reason for the event being redacted. |
Response format:
Parameter | Type | Description |
---|---|---|
event_id | string | A unique identifier for the event. |
Example request:
PUT /_matrix/client/r0/rooms/%21637q39766251%3Aexample.com/redact/bai2b1i9%3Amatrix.org/37 HTTP/1.1 Content-Type: application/json { "reason": "Indecent material" }
Response:
Status code 200:
An ID for the redaction event.
Example
{ "event_id": "$YUwQidLecu:example.com" }
The homeserver will create an m.room.create event when a room is created, which serves as the root of the event graph for this room. This event also has a creator key which contains the user ID of the room creator. It will also generate several other events in order to manage permissions in this room. This includes:
See Room Events for more information on these events. To create a room, a client has to use the following API.
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:
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
visibility | enum | 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"] |
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. |
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. |
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. |
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. |
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. |
creation_content | CreationContent | Extra keys, such as m.federate, to be added to the content of the m.room.create event. The server will clobber the following keys: creator, room_version. Future versions of the specification may allow the server to clobber 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 overriden by name and topic keys. |
preset | enum | 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 visbility 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"] |
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. |
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. |
Parameter | Type | Description |
---|---|---|
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. |
address | string | Required. The invitee's third party identifier. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The type of event to send. |
state_key | string | The state_key of the state event. Defaults to an empty string. |
content | object | Required. The content of the event. |
Response format:
Parameter | Type | Description |
---|---|---|
room_id | string | Required. The created room's ID. |
Example request:
POST /_matrix/client/r0/createRoom HTTP/1.1 Content-Type: application/json { "preset": "public_chat", "room_alias_name": "thepub", "name": "The Grand Duke Pub", "topic": "All about happy hour", "creation_content": { "m.federate": false } }
Responses:
Status code 200:
Information about the newly created room.
Example
{ "room_id": "!sefiuhWgwghwWgh:example.com" }
Status code 400:
The request is invalid. A meaningful errcode and description error text will be returned. Example reasons for rejection include:
Example
{ "errcode": "M_UNKNOWN", "error": "An unknown error occurred" }
Servers may host aliases for rooms with human-friendly names. Aliases take the form #friendlyname:server.name.
As room aliases are scoped to a particular homeserver domain name, it is likely that a homeserver will reject attempts to maintain aliases on other domain names. This specification does not provide a way for homeservers to send update requests to other servers. However, homeservers MUST handle GET requests to resolve aliases on other servers; they should do this using the federation API if necessary.
Rooms store a partial list of room aliases via the m.room.aliases state event. This alias list is partial because it cannot guarantee that the alias list is in any way accurate or up-to-date, as room aliases can point to different room IDs over time. Crucially, the aliases in this event are purely informational and SHOULD NOT be treated as accurate. They SHOULD be checked before they are used or shared with another user. If a room appears to have a room alias of #alias:example.com, this SHOULD be checked to make sure that the room's ID matches the room_id returned from the request.
Create a new mapping from room alias to room ID.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomAlias | string | Required. The room alias to set. |
JSON body parameters | ||
room_id | string | Required. The room ID to set. |
Example request:
PUT /_matrix/client/r0/directory/room/%23monkeys%3Amatrix.org HTTP/1.1 Content-Type: application/json { "room_id": "!abnjk1jdasj98:capuchins.com" }
Responses:
Status code 200:
The mapping was created.
Example
{}
Status code 409:
A room alias with that name already exists.
Example
{ "errcode": "M_UNKNOWN", "error": "Room alias #monkeys:matrix.org already exists." }
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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomAlias | string | Required. The room alias. |
Response format:
Parameter | 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. |
Example request:
GET /_matrix/client/r0/directory/room/%23monkeys%3Amatrix.org HTTP/1.1
Responses:
Status code 200:
The room ID and other information for this alias.
Example
{ "room_id": "!abnjk1jdasj98:capuchins.com", "servers": [ "capuchins.com", "matrix.org", "another.com" ] }
Status code 404:
There is no mapped room ID for this room alias.
Example
{ "errcode": "M_NOT_FOUND", "error": "Room alias #monkeys:matrix.org not found." }
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.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomAlias | string | Required. The room alias to remove. |
Example request:
DELETE /_matrix/client/r0/directory/room/%23monkeys%3Amatrix.org HTTP/1.1
Responses:
Status code 200:
The mapping was deleted.
Example
{}
Status code 404:
There is no mapped room ID for this room alias.
Example
{ "errcode": "M_NOT_FOUND", "error": "Room alias #monkeys:example.org not found." }
Note
This section is a work in progress.
Permissions for rooms are done via the concept of power levels - to do any action in a room a user must have a suitable power level. Power levels are stored as state events in a given room. The power levels required for operations and the power levels for users are defined in m.room.power_levels, where both a default and specific users' power levels can be set. By default all users have a power level of 0, other than the room creator whose power level defaults to 100. Users can grant other users increased power levels up to their own power level. For example, user A with a power level of 50 could increase the power level of user B to a maximum of level 50. Power levels for users are tracked per-room even if the user is not present in the room. The keys contained in m.room.power_levels determine the levels required for certain operations such as kicking, banning and sending state events. See m.room.power_levels for more information.
Clients may wish to assign names to particular power levels. A suggested mapping is as follows: - 0 User - 50 Moderator - 100 Admin
Users need to be a member of a room in order to send and receive events in that room. There are several states in which a user may be, in relation to a room:
There is an exception to the requirement that a user join a room before sending events to it: users may send an m.room.member event to a room with content.membership set to leave to reject an invitation if they have currently been invited to a room but have not joined it.
Some rooms require that users be invited to it before they can join; others allow anyone to join. Whether a given room is an "invite-only" room is determined by the room config key m.room.join_rules. It can have one of the following values:
The allowable state transitions of membership are:
/ban +------------------------------------------------------+ | | | +----------------+ +----------------+ | | | /leave | | | | | | v v | | /invite +--------+ +-------+ | | ------------>| invite |<----------| leave |----+ | | +--------+ /invite +-------+ | | | | | ^ | | | | | | | | | /join | +---------------+ | | | | | | /join if | | | | | | join_rules | | /ban | /unban | | | public /leave | | | | v v or | | | | +------+ /kick | | | | ------------>| join |-------------------+ | | | /join +------+ v | | if | +-----+ | | join_rules +-------------------------->| ban |-----+ | public /ban +-----+ | ^ ^ | | | | ----------------------------------------------+ +----------------------+ /ban
This API returns a list of the user's current rooms.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
joined_rooms | [string] | Required. The ID of each room in which the user has joined membership. |
Example request:
GET /_matrix/client/r0/joined_rooms HTTP/1.1
Response:
Status code 200:
A list of the rooms the user is in.
Example
{ "joined_rooms": [ "!foo:example.com" ] }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier (not alias) to which to invite the user. |
JSON body parameters | ||
user_id | string | Required. The fully qualified user ID of the invitee. |
Example request:
POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/invite HTTP/1.1 Content-Type: application/json { "user_id": "@cheeky_monkey:matrix.org" }
Responses:
Status code 200:
The user has been invited to join the room.
Example
{}
Status code 400:
The request is invalid. A meaningful errcode and description error text will be returned. Example reasons for rejection include:
Example
{ "errcode": "M_UNKNOWN", "error": "An unknown error occurred" }
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Note that this API requires a room ID, not alias. /join/{roomIdOrAlias} exists if you have a room alias.
This API starts a user participating 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.
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.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier (not alias) to join. |
JSON body parameters | ||
third_party_signed | Third Party Signed | A signature of an m.third_party_invite token to prove that this user owns a third party identity which has been invited to the room. |
Parameter | Type | Description |
---|---|---|
sender | string | Required. The Matrix ID of the user who issued the invite. |
mxid | string | Required. The Matrix ID of the invitee. |
token | string | Required. The state key of the m.third_party_invite event. |
signatures | Signatures | Required. A signatures object containing a signature of the entire signed object. |
Response format:
Parameter | Type | Description |
---|---|---|
room_id | string | Required. The joined room ID. |
Example request:
POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/join HTTP/1.1 Content-Type: application/json { "third_party_signed": { "sender": "@alice:example.org", "mxid": "@bob:example.org", "token": "random8nonce", "signatures": { "example.org": { "ed25519:0": "some9signature" } } } }
Responses:
Status code 200:
The room has been joined.
The joined room ID must be returned in the room_id field.
Example
{ "room_id": "!d41d8cd:matrix.org" }
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "You are not invited to this room." }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Note that this API takes either a room ID or alias, unlike /room/{roomId}/join.
This API starts a user participating 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.
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.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomIdOrAlias | string | Required. The room identifier or alias to join. |
query parameters | ||
server_name | [string] | The servers to attempt to join the room through. One of the servers must be participating in the room. |
JSON body parameters | ||
third_party_signed | Third Party Signed | A signature of an m.third_party_invite token to prove that this user owns a third party identity which has been invited to the room. |
Parameter | Type | Description |
---|---|---|
sender | string | Required. The Matrix ID of the user who issued the invite. |
mxid | string | Required. The Matrix ID of the invitee. |
token | string | Required. The state key of the m.third_party_invite event. |
signatures | Signatures | Required. A signatures object containing a signature of the entire signed object. |
Response format:
Parameter | Type | Description |
---|---|---|
room_id | string | Required. The joined room ID. |
Example request:
POST /_matrix/client/r0/join/%23monkeys%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 Content-Type: application/json { "third_party_signed": { "sender": "@alice:example.org", "mxid": "@bob:example.org", "token": "random8nonce", "signatures": { "example.org": { "ed25519:0": "some9signature" } } } }
Responses:
Status code 200:
The room has been joined.
The joined room ID must be returned in the room_id field.
Example
{ "room_id": "!d41d8cd:matrix.org" }
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "You are not invited to this room." }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
A user can leave a room to stop receiving events for that room. A user must have been invited to or have joined the room before they are eligible to leave the room. Leaving a room to which the user has been invited rejects the invite. Once a user leaves a room, it will no longer appear in the response to the /sync API unless it is explicitly requested via a filter with the include_leave field set to true.
Whether or not they actually joined the room, if the room is an "invite-only" room the user will need to be re-invited before they can re-join the room.
A user can also forget a room which they have left. Rooms which have been forgotten will never appear the response to the /sync API, until the user re-joins or is re-invited.
A user may wish to force another user to leave a room. This can be done by 'kicking' the other user. To do so, the user performing the kick MUST have the required power level. Once a user has been kicked, the behaviour is the same as if they had left of their own accord. In particular, the user is free to re-join if the room is not "invite-only".
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier to leave. |
Example request:
POST /_matrix/client/r0/rooms/%21nkl290a%3Amatrix.org/leave HTTP/1.1
Responses:
Status code 200:
The room has been left.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier to forget. |
Example request:
POST /_matrix/client/r0/rooms/%21au1ba7o%3Amatrix.org/forget HTTP/1.1
Responses:
Status code 200:
The room has been forgotten.
Example
{}
Status code 400:
The user has not left the room
Example
{ "errcode": "M_UNKNOWN", "error": "User @example:matrix.org is in room !au1ba7o:matrix.org" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier (not alias) from which the user should be kicked. |
JSON body parameters | ||
user_id | string | Required. The fully qualified user ID of the user being kicked. |
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. |
Example request:
POST /_matrix/client/r0/rooms/%21e42d8c%3Amatrix.org/kick HTTP/1.1 Content-Type: application/json { "reason": "Telling unfunny jokes", "user_id": "@cheeky_monkey:matrix.org" }
Responses:
Status code 200:
The user has been kicked from the room.
Example
{}
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to kick from this room." }
A user may decide to ban another user in a room. 'Banning' forces the target user to leave the room and prevents them from re-joining the room. A banned user will not be treated as a joined user, and so will not be able to send or receive events in the room. In order to ban someone, the user performing the ban MUST have the required power level. To ban a user, a request should be made to /rooms/<room_id>/ban with:
{ "user_id": "<user id to ban>" "reason": "string: <reason for the ban>" }
Banning a user adjusts the banned member's membership state to ban. 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>:
{ "membership": "ban" }
A user must be explicitly unbanned with a request to /rooms/<room_id>/unban before they can re-join the room or be re-invited.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier (not alias) from which the user should be banned. |
JSON body parameters | ||
user_id | string | Required. The fully qualified user ID of the user being banned. |
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. |
Example request:
POST /_matrix/client/r0/rooms/%21e42d8c%3Amatrix.org/ban HTTP/1.1 Content-Type: application/json { "reason": "Telling unfunny jokes", "user_id": "@cheeky_monkey:matrix.org" }
Responses:
Status code 200:
The user has been kicked and banned from the room.
Example
{}
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to ban from this room." }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier (not alias) from which the user should be unbanned. |
JSON body parameters | ||
user_id | string | Required. The fully qualified user ID of the user being unbanned. |
Example request:
POST /_matrix/client/r0/rooms/%21e42d8c%3Amatrix.org/unban HTTP/1.1 Content-Type: application/json { "user_id": "@cheeky_monkey:matrix.org" }
Responses:
Status code 200:
The user has been unbanned from the room.
Example
{}
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to unban from this room." }
Gets the visibility of a given room on the server's public room directory.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room ID. |
Response format:
Parameter | Type | Description |
---|---|---|
visibility | enum | The visibility of the room in the directory. One of: ["private", "public"] |
Example request:
GET /_matrix/client/r0/directory/list/room/%21curbf%3Amatrix.org HTTP/1.1
Responses:
Status code 200:
The visibility of the room in the directory
Example
{ "visibility": "public" }
Status code 404:
The room is not known to the server
Example
{ "errcode": "M_NOT_FOUND", "error": "Room not found" }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room ID. |
JSON body parameters | ||
visibility | enum | The new visibility setting for the room. Defaults to 'public'. One of: ["private", "public"] |
Example request:
PUT /_matrix/client/r0/directory/list/room/%21curbf%3Amatrix.org HTTP/1.1 Content-Type: application/json { "visibility": "public" }
Responses:
Status code 200:
The visibility was updated, or no change was needed.
Example
{}
Status code 404:
The room is not known to the server
Example
{ "errcode": "M_NOT_FOUND", "error": "Room not found" }
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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
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. |
server | string | The server to fetch the public room lists from. Defaults to the local server. |
Response format:
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
aliases | [string] | Aliases of the room. May be empty. |
canonical_alias | string | The canonical alias of the room, if any. |
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. |
topic | string | The topic of the room, if any. |
world_readable | boolean | Required. Whether the room may be viewed by guest users without joining. |
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. |
avatar_url | string | The URL for the room's avatar, if one is set. |
Example request:
GET /_matrix/client/r0/publicRooms HTTP/1.1
Response:
Status code 200:
A list of the rooms on the server.
Example
{ "chunk": [ { "aliases": [ "#murrays:cheese.bar" ], "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", "guest_can_join": false, "name": "CHEESE", "num_joined_members": 37, "room_id": "!ol19s:bleecker.street", "topic": "Tasty tasty cheese", "world_readable": true } ], "next_batch": "p190q", "prev_batch": "p1902", "total_room_count_estimate": 115 }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
server | string | The server to fetch the public room lists from. Defaults to the local server. |
JSON body parameters | ||
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. |
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. |
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. |
Parameter | Type | Description |
---|---|---|
generic_search_term | string | A string to search for in the room metadata, e.g. name, topic, canonical alias etc. (Optional). |
Response format:
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
aliases | [string] | Aliases of the room. May be empty. |
canonical_alias | string | The canonical alias of the room, if any. |
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. |
topic | string | The topic of the room, if any. |
world_readable | boolean | Required. Whether the room may be viewed by guest users without joining. |
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. |
avatar_url | string | The URL for the room's avatar, if one is set. |
Example request:
POST /_matrix/client/r0/publicRooms HTTP/1.1 Content-Type: application/json { "limit": 10, "filter": { "generic_search_term": "foo" }, "include_all_networks": false, "third_party_instance_id": "irc" }
Response:
Status code 200:
A list of the rooms on the server.
Example
{ "chunk": [ { "aliases": [ "#murrays:cheese.bar" ], "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", "guest_can_join": false, "name": "CHEESE", "num_joined_members": 37, "room_id": "!ol19s:bleecker.street", "topic": "Tasty tasty cheese", "world_readable": true } ], "next_batch": "p190q", "prev_batch": "p1902", "total_room_count_estimate": 115 }
Performs a search for users on the homeserver. 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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
search_term | string | Required. The term to search for |
limit | integer | The maximum number of results to return. Defaults to 10. |
Response format:
Parameter | Type | Description |
---|---|---|
results | [User] | Required. Ordered by rank and then whether or not profile info is available. |
limited | boolean | Required. Indicates if the result list has been truncated by the limit. |
Parameter | Type | Description |
---|---|---|
user_id | string | Required. The user's matrix user ID. |
display_name | string | The display name of the user, if one exists. |
avatar_url | string | The avatar url, as an MXC, if one exists. |
Example request:
POST /_matrix/client/r0/user_directory/search HTTP/1.1 Content-Type: application/json { "search_term": "foo", "limit": 10 }
Responses:
Status code 200:
The results of the search.
Example
{ "results": [ { "user_id": "@foo:bar.com", "display_name": "Foo", "avatar_url": "mxc://bar.com/foo" } ], "limited": false }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose display name to set. |
JSON body parameters | ||
displayname | string | The new display name for this user. |
Example request:
PUT /_matrix/client/r0/profile/%40alice%3Aexample.com/displayname HTTP/1.1 Content-Type: application/json { "displayname": "Alice Margatroid" }
Responses:
Status code 200:
The display name was set.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose display name to get. |
Response format:
Parameter | Type | Description |
---|---|---|
displayname | string | The user's display name if they have set one, otherwise not present. |
Example request:
GET /_matrix/client/r0/profile/%40alice%3Aexample.com/displayname HTTP/1.1
Responses:
Status code 200:
The display name for this user.
Example
{ "displayname": "Alice Margatroid" }
Status code 404:
There is no display name for this user or this user does not exist.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose avatar URL to set. |
JSON body parameters | ||
avatar_url | string | The new avatar URL for this user. |
Example request:
PUT /_matrix/client/r0/profile/%40alice%3Aexample.com/avatar_url HTTP/1.1 Content-Type: application/json { "avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34" }
Responses:
Status code 200:
The avatar URL was set.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose avatar URL to get. |
Response format:
Parameter | Type | Description |
---|---|---|
avatar_url | string | The user's avatar URL if they have set one, otherwise not present. |
Example request:
GET /_matrix/client/r0/profile/%40alice%3Aexample.com/avatar_url HTTP/1.1
Responses:
Status code 200:
The avatar URL for this user.
Example
{ "avatar_url": "mxc://matrix.org/SDGdghriugerRg" }
Status code 404:
There is no avatar URL for this user or this user does not exist.
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. This API may return keys which are not limited to displayname or avatar_url.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose profile information to get. |
Response format:
Parameter | Type | Description |
---|---|---|
avatar_url | string | 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. |
Example request:
GET /_matrix/client/r0/profile/%40alice%3Aexample.com HTTP/1.1
Responses:
Status code 200:
The avatar URL for this user.
Example
{ "avatar_url": "mxc://matrix.org/SDGdghriugerRg", "displayname": "Alice Margatroid" }
Status code 404:
There is no profile information for this user or this user does not exist.
Because the profile display name and avatar information are likely to be used in many places of a client's display, changes to these fields cause an automatic propagation event to occur, informing likely-interested parties of the new values. This change is conveyed using two separate mechanisms:
Both of these should be done automatically by the homeserver when a user successfully changes their display name or avatar URL fields.
Additionally, when homeservers emit room membership events for their own users, they should include the display name and avatar URL fields in these events so that clients already have these details to hand, and do not have to perform extra round trips to query it.
Homeservers SHOULD implement rate limiting to reduce the risk of being overloaded. If a request is refused due to rate limiting, it should return a standard error response of the form:
{ "errcode": "M_LIMIT_EXCEEDED", "error": "string", "retry_after_ms": integer (optional) }
The retry_after_ms key SHOULD be included to tell the client how long they have to wait in milliseconds before they can try again.
Modules are parts of the Client-Server API which are not universal to all endpoints. Modules are strictly defined within this specification and should not be mistaken for experimental extensions or optional features. A compliant server implementation MUST support all modules and supporting specification (unless the implementation only targets clients of certain profiles, in which case only the required modules for those feature profiles MUST be implemented). A compliant client implementation MUST support all the required modules and supporting specification for the Feature Profile it targets.
Matrix supports many different kinds of clients: from embedded IoT devices to desktop clients. Not all clients can provide the same feature sets as other clients e.g. due to lack of physical hardware such as not having a screen. Clients can fall into one of several profiles and each profile contains a set of features that the client MUST support. This section details a set of "feature profiles". Clients are expected to implement a profile in its entirety in order for it to be classified as that profile.
Module / Profile | Web | Mobile | Desktop | CLI | Embedded |
---|---|---|---|---|---|
Instant Messaging | Required | Required | Required | Required | Optional |
Direct Messaging | Required | Required | Required | Required | Optional |
Mentions | Required | Required | Required | Optional | Optional |
Presence | Required | Required | Required | Required | Optional |
Push Notifications | Optional | Required | Optional | Optional | Optional |
Receipts | Required | Required | Required | Required | Optional |
Fully read markers | Optional | Optional | Optional | Optional | Optional |
Typing Notifications | Required | Required | Required | Required | Optional |
VoIP | Required | Required | Required | Optional | Optional |
Ignoring Users | Required | Required | Required | Optional | Optional |
Reporting Content | Optional | Optional | Optional | Optional | Optional |
Content Repository | Required | Required | Required | Optional | Optional |
Managing History Visibility | Required | Required | Required | Required | Optional |
Server Side Search | Optional | Optional | Optional | Optional | Optional |
Room Upgrades | Required | Required | Required | Required | Optional |
Server Administration | Optional | Optional | Optional | Optional | Optional |
Event Context | Optional | Optional | Optional | Optional | Optional |
Third Party Networks | Optional | Optional | Optional | Optional | Optional |
Send-to-Device Messaging | Optional | Optional | Optional | Optional | Optional |
Device Management | Optional | Optional | Optional | Optional | Optional |
End-to-End Encryption | Optional | Optional | Optional | Optional | Optional |
Guest Accounts | Optional | Optional | Optional | Optional | Optional |
Room Previews | Optional | Optional | Optional | Optional | Optional |
Client Config | Optional | Optional | Optional | Optional | Optional |
SSO Login | Optional | Optional | Optional | Optional | Optional |
OpenID | Optional | Optional | Optional | Optional | Optional |
Stickers | Optional | Optional | Optional | Optional | Optional |
Server ACLs | Optional | Optional | Optional | Optional | Optional |
Server Notices | Optional | Optional | Optional | Optional | Optional |
Please see each module for more details on what clients need to implement.
This is a web page which heavily uses Matrix for communication. Single-page web apps would be classified as a stand-alone web client, as would multi-page web apps which use Matrix on nearly every page.
This is a Matrix client specifically designed for consumption on mobile devices. This is typically a mobile app but need not be so provided the feature set can be reached (e.g. if a mobile site could display push notifications it could be classified as a mobile client).
This is a native GUI application which can run in its own environment outside a browser.
This is a client which is used via a text-based terminal.
This is a client which is embedded into another application or an embedded device.
This is a Matrix client which is embedded in another website, e.g. using iframes. These embedded clients are typically for a single purpose related to the website in question, and are not intended to be fully-fledged communication apps.
This is a client which is typically running on an embedded device such as a kettle, fridge or car. These clients tend to perform a few operations and run in a resource constrained environment. Like embedded applications, they are not intended to be fully-fledged communication systems.
This module adds support for sending human-readable messages to a room. It also adds support for associating human-readable information with the room itself such as a room name and topic.
Message Event
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. For more information on msgtypes, see m.room.message msgtypes.
Content Key | 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": "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 } }
{ "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 } }
{ "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 } }
{ "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 } }
{ "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 } }
{ "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 } }
{ "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 } }
{ "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 } }
{ "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 } }
Message Event
NB: Usage of this event is discouraged in favour of the receipts module. Most clients will not recognise this event. Feedback events are events sent to acknowledge a message in some way. There are two supported acknowledgements: delivered (sent when the event has been received) and read (sent when the event has been observed by the end-user). The target_event_id should reference the m.room.message event being acknowledged.
Content Key | Type | Description |
---|---|---|
target_event_id | string | Required. The event that this feedback is related to. |
type | enum | Required. The type of feedback. One of: ["delivered", "read"] |
Example:
{ "content": { "target_event_id": "$WEIGFHFW:localhost", "type": "delivered" }, "event_id": "$143273582443PhrSn:example.org", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "sender": "@example:example.org", "type": "m.room.message.feedback", "unsigned": { "age": 1234 } }
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.
A room with an m.room.name event with an absent, null, or empty name field 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.
Content Key | Type | Description |
---|---|---|
name | string | Required. The name of the room. This MUST NOT exceed 255 bytes. |
Example:
{ "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 } }
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.
Content Key | Type | Description |
---|---|---|
topic | string | Required. The topic text. |
Example:
{ "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 } }
A picture that is associated with the room. This can be displayed alongside the room information.
Content Key | Type | Description |
---|---|---|
info | ImageInfo | Metadata about the image referred to in url. |
url | string | Required. The URL to the image. |
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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_url | string | The URL (typically MXC URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted. |
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. |
ThumbnailInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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. |
Example:
{ "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 } }
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.
Content Key | Type | Description |
---|---|---|
pinned | [string] | Required. An ordered list of event IDs to pin. |
Example:
{ "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 } }
Each m.room.message MUST have a msgtype key which identifies the type of message being sent. Each type has their own required and optional keys, as outlined below. If a client cannot display the given msgtype then it SHOULD display the fallback plain text body key instead.
Some message types support HTML in the event content that clients should prefer to display if available. Currently m.text, m.emote, and m.notice support an additional format parameter of org.matrix.custom.html. When this field is present, a formatted_body with the HTML must be provided. The plain text version of the HTML should be provided in the body.
Clients should limit the HTML they render to avoid Cross-Site Scripting, HTML injection, and similar attacks. The strongly suggested set of HTML tags to permit, denying the use and rendering of anything else, is: font, del, h1, h2, h3, h4, h5, h6, blockquote, p, a, ul, ol, sup, sub, li, b, i, u, strong, em, strike, code, hr, br, div, table, thead, tbody, tr, th, td, caption, pre, span, img.
Not all attributes on those tags should be permitted as they may be avenues for other disruption attempts, such as adding onclick handlers or excessively large text. Clients should only permit the attributes listed for the tags below. Where data-mx-bg-color and data-mx-color are listed, clients should translate the value (a 6-character hex color code) to the appropriate CSS/attributes for the tag.
font: | data-mx-bg-color, data-mx-color |
---|---|
span: | data-mx-bg-color, data-mx-color |
a: | name, target, href (provided the value is not relative and has a scheme matching one of: https, http, ftp, mailto, magnet) |
img: | width, height, alt, title, src (provided it is a Matrix Content (MXC) URI) |
ol: | start |
code: | class (only classes which start with language- for syntax highlighting) |
Additionally, web clients should ensure that all a tags get a rel="noopener" to prevent the target page from referencing the client's tab/window.
Tags must not be nested more than 100 levels deep. Clients should only support the subset of tags they can render, falling back to other representations of the tags where possible. For example, a client may not be able to render tables correctly and instead could fall back to rendering tab-delimited text.
In addition to not rendering unsafe HTML, clients should not emit unsafe HTML in events. Likewise, clients should not generate HTML that is not needed, such as extra paragraph tags surrounding text due to Rich Text Editors. HTML included in events should otherwise be valid, such as having appropriate closing tags, appropriate attributes (considering the custom ones defined in this specification), and generally valid structure.
A special tag, mx-reply, may appear on rich replies (described below) and should be allowed if, and only if, the tag appears as the very first tag in the formatted_body. The tag cannot be nested and cannot be located after another tag in the tree. Because the tag contains HTML, an mx-reply is expected to have a partner closing tag and should be treated similar to a div. Clients that support rich replies will end up stripping the tag and its contents and therefore may wish to exclude the tag entirely.
Note
A future iteration of the specification will support more powerful and extensible message formatting options, such as the proposal MSC1225.
This message is the most basic message and is used to represent text.
Content Key | Type | Description |
---|---|---|
body | string | Required. The body of the message. |
msgtype | string | Required. Must be 'm.text'. |
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. |
Example:
{ "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 } }
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.
Content Key | Type | Description |
---|---|---|
body | string | Required. The emote action to perform. |
msgtype | string | Required. Must be 'm.emote'. |
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. |
Example:
{ "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 } }
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.
Content Key | Type | Description |
---|---|---|
body | string | Required. The notice text to send. |
msgtype | string | Required. Must be 'm.notice'. |
Example:
{ "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 } }
This message represents a single image and an optional thumbnail.
Content Key | Type | Description |
---|---|---|
body | string | Required. A textual representation of the image. This could be the alt text of the image, the filename of the image, or some kind of content description for accessibility e.g. 'image attachment'. |
info | ImageInfo | Metadata about the image referred to in url. |
msgtype | string | Required. Must be 'm.image'. |
url | string | Required. Required if the file is unencrypted. The URL (typically MXC URI) to the image. |
file | EncryptedFile | Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption. |
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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_url | string | The URL (typically MXC URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted. |
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. |
ThumbnailInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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. |
Example:
{ "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 } }
This message represents a generic file.
Content Key | Type | Description |
---|---|---|
body | string | Required. A human-readable description of the file. This is recommended to be the filename of the original upload. |
filename | string | The original filename of the uploaded file. |
info | FileInfo | Information about the file referred to in url. |
msgtype | string | Required. Must be 'm.file'. |
url | string | Required. Required if the file is unencrypted. The URL (typically MXC URI) to the file. |
file | EncryptedFile | Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption. |
FileInfo Key | Type | Description |
---|---|---|
mimetype | string | The mimetype of the file e.g. application/msword. |
size | integer | The size of the file in bytes. |
thumbnail_url | string | The URL to the thumbnail of the file. Only present if the thumbnail is unencrypted. |
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. |
ThumbnailInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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. |
Example:
{ "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 } }
This message represents a single audio clip.
Content Key | Type | Description |
---|---|---|
body | string | Required. A description of the audio e.g. 'Bee Gees - Stayin' Alive', or some kind of content description for accessibility e.g. 'audio attachment'. |
info | AudioInfo | Metadata for the audio clip referred to in url. |
msgtype | string | Required. Must be 'm.audio'. |
url | string | Required. Required if the file is not encrypted. The URL (typically MXC URI) to the audio clip. |
file | EncryptedFile | Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption. |
AudioInfo Key | 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. |
Example:
{ "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 } }
This message represents a real-world location.
Content Key | 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 representing this location. |
msgtype | string | Required. Must be 'm.location'. |
info | LocationInfo |
LocationInfo Key | Type | Description |
---|---|---|
thumbnail_url | string | The URL to the thumbnail of the file. Only present if the thumbnail is unencrypted. |
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. |
ThumbnailInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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. |
Example:
{ "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 } }
This message represents a single video clip.
Content Key | Type | Description |
---|---|---|
body | string | Required. A description of the video e.g. 'Gangnam style', or some kind of content description for accessibility e.g. 'video attachment'. |
info | VideoInfo | Metadata about the video clip referred to in url. |
msgtype | string | Required. Must be 'm.video'. |
url | string | Required. Required if the file is unencrypted. The URL (typically MXC URI) to the video clip. |
file | EncryptedFile | Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption. |
VideoInfo Key | Type | Description |
---|---|---|
duration | integer | The duration of the video in milliseconds. |
h | integer | The height of the video in pixels. |
w | integer | The width 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_url | string | The URL (typically MXC URI) to an image thumbnail of the video clip. Only present if the thumbnail is unencrypted. |
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. |
ThumbnailInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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. |
Example:
{ "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 } }
Clients SHOULD verify the structure of incoming events to ensure that the expected keys exist and that they are of the right type. Clients can discard malformed events or display a placeholder message to the user. Redacted m.room.message events MUST be removed from the client. This can either be replaced with placeholder text (e.g. "[REDACTED]") or the redacted message can be removed entirely from the messages view.
Events which have attachments (e.g. m.image, m.file) SHOULD be uploaded using the content repository module where available. The resulting mxc:// URI can then be used in the url key.
Clients MAY include a client generated thumbnail image for an attachment under a info.thumbnail_url key. The thumbnail SHOULD also be a mxc:// URI. Clients displaying events with attachments can either use the client generated thumbnail or ask its homeserver to generate a thumbnail from the original attachment using the content repository module.
In the event of send failure, clients SHOULD retry requests using an exponential-backoff algorithm for a certain amount of time T. It is recommended that T is no longer than 5 minutes. After this time, the client should stop retrying and mark the message as "unsent". Users should be able to manually resend unsent messages.
Users may type several messages at once and send them all in quick succession. Clients SHOULD preserve the order in which they were sent by the user. This means that clients should wait for the response to the previous request before sending the next request. This can lead to head-of-line blocking. In order to reduce the impact of head-of-line blocking, clients should use a queue per room rather than a global queue, as ordering is only relevant within a single room rather than between rooms.
Messages SHOULD appear immediately in the message view when a user presses the "send" button. This should occur even if the message is still sending. This is referred to as "local echo". Clients SHOULD implement "local echo" of messages. Clients MAY display messages in a different format to indicate that the server has not processed the message. This format should be removed when the server responds.
Clients need to be able to match the message they are sending with the same message which they receive from the event stream. The echo of the same message from the event stream is referred to as "remote echo". Both echoes need to be identified as the same message in order to prevent duplicate messages being displayed. Ideally this pairing would occur transparently to the user: the UI would not flicker as it transitions from local to remote. Flickering can be reduced through clients making use of the transaction ID they used to send a particular event. The transaction ID used will be included in the event's unsigned data as transaction_id when it arrives through the event stream.
Clients unable to make use of the transaction ID are likely to experience flickering when the remote echo arrives on the event stream before the request to send the message completes. In that case the event arrives before the client has obtained an event ID, making it impossible to identify it as a remote echo. This results in the client displaying the message twice for some time (depending on the server responsiveness) before the original request to send the message completes. Once it completes, the client can take remedial actions to remove the duplicate event by looking for duplicate event IDs.
Clients may wish to show the human-readable display name of a room member as part of a membership list, or when they send a message. However, different members may have conflicting display names. Display names MUST be disambiguated before showing them to the user, in order to prevent spoofing of other users.
To ensure this is done consistently across clients, clients SHOULD use the following algorithm to calculate a disambiguated display name for a given user:
Developers should take note of the following when implementing the above algorithm:
Clients may wish to show the display name and avatar URL of the room member who sent a message. This can be achieved by inspecting the m.room.member state event for that user ID (see Calculating the display name for a user).
When a user paginates the message history, clients may wish to show the historical display name and avatar URL for a room member. This is possible because older m.room.member events are returned when paginating. This can be implemented efficiently by keeping two sets of room state: old and current. As new events arrive and/or the user paginates back in time, these two sets of state diverge from each other. New events update the current state and paginated events update the old state. When paginated events are processed sequentially, the old state represents the state of the room at the time the event was sent. This can then be used to set the historical display name and avatar URL.
Clients may wish to show a human-readable name for a room. There are a number of possibilities for choosing a useful name. To ensure that rooms are named consistently across clients, clients SHOULD use the following algorithm to choose a name:
Clients SHOULD internationalise the room name to the user's language when using the m.heroes to calculate the name. Clients SHOULD use minimum 5 heroes to calculate room names where possible, but may use more or less to fit better with their user experience.
In some cases, events may wish to reference other events. This could be to form a thread of messages for the user to follow along with, or to provide more context as to what a particular event is describing. Currently, the only kind of relation defined is a "rich reply" where a user may reference another message to create a thread-like conversation.
Relationships are defined under an m.relates_to key in the event's content. If the event is of the type m.room.encrypted, the m.relates_to key MUST NOT be covered by the encryption and instead be put alongside the encryption information held in the content.
Users may wish to reference another message when forming their own message, and clients may wish to better embed the referenced message for the user to have a better context for the conversation being had. This sort of embedding another message in a message is known as a "rich reply", or occasionally just a "reply".
A rich reply is formed through use of an m.relates_to relation for m.in_reply_to where a single key, event_id, is used to reference the event being replied to. The referenced event ID SHOULD belong to the same room where the reply is being sent. Clients should be cautious of the event ID belonging to another room, or being invalid entirely. Rich replies can only be constructed in the form of m.room.message events with a msgtype of m.text or m.notice. Due to the fallback requirements, rich replies cannot be constructed for types of m.emote, m.file, etc. Rich replies may reference any other m.room.message event, however. Rich replies may reference another event which also has a rich reply, infinitely.
An m.in_reply_to relationship looks like the following:
{ ... "type": "m.room.message", "content": { "msgtype": "m.text", "body": "<body including fallback>", "format": "org.matrix.custom.html", "formatted_body": "<HTML including fallback>", "m.relates_to": { "m.in_reply_to": { "event_id": "$another:event.com" } } } }
Some clients may not have support for rich replies and therefore need a fallback to use instead. Clients that do not support rich replies should render the event as if rich replies were not special.
Clients that do support rich replies MUST provide the fallback format on replies, and MUST strip the fallback before rendering the reply. Rich replies MUST have a format of org.matrix.custom.html and therefore a formatted_body alongside the body and appropriate msgtype. The specific fallback text is different for each msgtype, however the general format for the body is:
> <@alice:example.org> This is the original body This is where the reply goes
The formatted_body should use the following template:
<mx-reply> <blockquote> <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a> <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a> <br /> <!-- This is where the related event's HTML would be. --> </blockquote> </mx-reply> This is where the reply goes.
If the related event does not have a formatted_body, the event's body should be considered after encoding any HTML special characters. Note that the href in both of the anchors use a matrix.to URI.
Clients which support rich replies MUST strip the fallback from the event before rendering the event. This is because the text provided in the fallback cannot be trusted to be an accurate representation of the event. After removing the fallback, clients are recommended to represent the event referenced by m.in_reply_to similar to the fallback's representation, although clients do have creative freedom for their user interface. Clients should prefer the formatted_body over the body, just like with other m.room.message events.
To strip the fallback on the body, the client should iterate over each line of the string, removing any lines that start with the fallback prefix ("> ", including the space, without quotes) and stopping when a line is encountered without the prefix. This prefix is known as the "fallback prefix sequence".
To strip the fallback on the formatted_body, the client should remove the entirety of the mx-reply tag.
Using the prefix sequence, the first line of the related event's body should be prefixed with the user's ID, followed by each line being prefixed with the fallback prefix sequence. For example:
> <@alice:example.org> This is the first line > This is the second line This is the reply
The formatted_body uses the template defined earlier in this section.
Similar to the fallback for m.text, each line gets prefixed with the fallback prefix sequence. However an asterisk should be inserted before the user's ID, like so:
> * <@alice:example.org> feels like today is going to be a great day This is the reply
The formatted_body has a subtle difference for the template where the asterisk is also inserted ahead of the user's ID:
<mx-reply> <blockquote> <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a> * <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a> <br /> <!-- This is where the related event's HTML would be. --> </blockquote> </mx-reply> This is where the reply goes.
The related event's body would be a file name, which may not be very descriptive. The related event should additionally not have a format or formatted_body in the content - if the event does have a format and/or formatted_body, those fields should be ignored. Because the filename alone may not be descriptive, the related event's body should be considered to be "sent a file." such that the output looks similar to the following:
> <@alice:example.org> sent a file. This is the reply
<mx-reply> <blockquote> <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a> <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a> <br /> sent a file. </blockquote> </mx-reply> This is where the reply goes.
For m.image, the text should be "sent an image.". For m.video, the text should be "sent a video.". For m.audio, the text should be "sent an audio file".
Homeservers SHOULD reject m.room.message events which don't have a msgtype key, or which don't have a textual body key, with an HTTP status code of 400.
Messages sent using this module are not encrypted, although end to end encryption is in development (see E2E module).
Clients should sanitise all displayed keys for unsafe HTML to prevent Cross-Site Scripting (XSS) attacks. This includes room names and topics.
This module outlines how two users in a room can set up a Voice over IP (VoIP) call to each other. Voice and video calls are built upon the WebRTC 1.0 standard. Call signalling is achieved by sending message events to the room. In this version of the spec, only two-party communication is supported (e.g. between two peers, or between a peer and a multi-point conferencing unit). This means that clients MUST only send call events to rooms with exactly two participants.
Message Event
This event is sent by the caller when they wish to establish a call.
Content Key | Type | Description |
---|---|---|
call_id | string | Required. A unique identifier for the call. |
offer | Offer | Required. The session description object |
version | integer | Required. The version of the VoIP specification this message adheres to. This specification is version 0. |
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 Key | Type | Description |
---|---|---|
type | string | Required. The type of session description. Must be 'offer'. |
sdp | string | Required. The SDP text of the session description. |
Example:
{ "content": { "call_id": "12345", "lifetime": 60000, "offer": { "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]", "type": "offer" }, "version": 0 }, "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 } }
Message Event
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.
Content Key | Type | Description |
---|---|---|
call_id | string | Required. The ID of the call this event relates to. |
candidates | [Candidate] | Required. Array of objects describing the candidates. |
version | integer | Required. The version of the VoIP specification this messages adheres to. This specification is version 0. |
Candidate Key | Type | Description |
---|---|---|
sdpMid | string | Required. The SDP media type this candidate is intended for. |
sdpMLineIndex | number | Required. The index of the SDP 'm' line this candidate is intended for. |
candidate | string | Required. The SDP 'a' line of the candidate. |
Example:
{ "content": { "call_id": "12345", "candidates": [ { "candidate": "candidate:863018703 1 udp 2122260223 10.9.64.156 43670 typ host generation 0", "sdpMLineIndex": 0, "sdpMid": "audio" } ], "version": 0 }, "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 } }
Message Event
This event is sent by the callee when they wish to answer the call.
Content Key | Type | Description |
---|---|---|
call_id | string | Required. The ID of the call this event relates to. |
answer | Answer | Required. The session description object |
version | number | Required. |
Answer Key | Type | Description |
---|---|---|
type | string | Required. The type of session description. Must be 'answer'. |
sdp | string | Required. The SDP text of the session description. |
Example:
{ "content": { "answer": { "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]", "type": "answer" }, "call_id": "12345", "lifetime": 60000, "version": 0 }, "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 } }
Message Event
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.
Content Key | Type | Description |
---|---|---|
call_id | string | Required. The ID of the call this event relates to. |
version | integer | Required. The version of the VoIP specification this message adheres to. This specification is version 0. |
reason | enum | Optional error reason for the hangup. This should not be provided when the user naturally ends or rejects the call. When there was an error in the call negotiation, this should be ice_failed for when ICE negotiation fails or invite_timeout for when the other party did not answer in time. One of: ["ice_failed", "invite_timeout"] |
Example:
{ "content": { "call_id": "12345", "version": 0 }, "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 } }
A call is set up with message events exchanged as follows:
Caller Callee [Place Call] m.call.invite -----------> m.call.candidate --------> [..candidates..] --------> [Answers call] <--------------- m.call.answer [Call is active and ongoing] <--------------- m.call.hangup
Or a rejected call:
Caller Callee m.call.invite ------------> m.call.candidate ---------> [..candidates..] ---------> [Rejects call] <-------------- m.call.hangup
Calls are negotiated according to the WebRTC specification.
"Glare" is a problem which occurs when two users call each other at roughly the same time. This results in the call failing to set up as there already is an incoming/outgoing call. A glare resolution algorithm can be used to determine which call to hangup and which call to answer. If both clients implement the same algorithm then they will both select the same call and the call will be successfully connected.
As calls are "placed" to rooms rather than users, the glare resolution algorithm outlined below is only considered for calls which are to the same room. The algorithm is as follows:
The call setup should appear seamless to the user as if they had simply placed a call and the other party had accepted. This means any media stream that had been setup for use on a call should be transferred and used for the call that replaces it.
The homeserver MAY provide a TURN server which clients can use to contact the remote party. The following HTTP API endpoints will be used by clients in order to get information about the TURN server.
This API provides credentials for the client to use when initiating calls.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
username | string | Required. The username to use. |
password | string | Required. The password to use. |
uris | [string] | Required. A list of TURN URIs |
ttl | integer | Required. The time-to-live in seconds |
Example request:
GET /_matrix/client/r0/voip/turnServer HTTP/1.1
Responses:
Status code 200:
The TURN server credentials.
Example
{ "username": "1443779631:@user:example.com", "password": "JlKfBy1QwLrO20385QyAtEyIv0=", "uris": [ "turn:turn.example.com:3478?transport=udp", "turn:10.20.30.40:3478?transport=tcp", "turns:10.20.30.40:443?transport=tcp" ], "ttl": 86400 }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Calls should only be placed to rooms with one other user in them. If they are placed to group chat rooms it is possible that another user will intercept and answer the call.
Users may wish to be informed when another user is typing in a room. This can be achieved using typing notifications. These are ephemeral events scoped to a room_id. This means they do not form part of the Event Graph but still have a room_id key.
Informs the client of the list of users currently typing.
Content Key | Type | Description |
---|---|---|
user_ids | [string] | Required. The list of user IDs typing in this room, if any. |
Example:
{ "content": { "user_ids": [ "@alice:matrix.org", "@bob:example.com" ] }, "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "type": "m.typing" }
When a client receives an m.typing event, it MUST use the user ID list to REPLACE its knowledge of every user who is currently typing. The reason for this is that the server does not remember users who are not currently typing as that list gets big quickly. The client should mark as not typing any user ID who is not in that list.
It is recommended that clients store a boolean indicating whether the user is typing or not. Whilst this value is true a timer should fire periodically every N seconds to send a typing HTTP request. The value of N is recommended to be no more than 20-30 seconds. This request should be re-sent by the client to continue informing the server the user is still typing. As subsequent requests will replace older requests, a safety margin of 5 seconds before the expected timeout runs out is recommended. When the user stops typing, the state change of the boolean to false should trigger another HTTP request to inform the server that the user has stopped typing.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user who has started to type. |
roomId | string | Required. The room in which the user is typing. |
JSON body parameters | ||
typing | boolean | Required. Whether the user is typing or not. If false, the timeout key can be omitted. |
timeout | integer | The length of time in milliseconds to mark this user as typing. |
Example request:
PUT /_matrix/client/r0/rooms/%21wefh3sfukhs%3Aexample.com/typing/%40alice%3Aexample.com HTTP/1.1 Content-Type: application/json { "typing": true, "timeout": 30000 }
Responses:
Status code 200:
The new typing state was set.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Clients may not wish to inform everyone in a room that they are typing and instead only specific users in the room.
This module adds in support for receipts. These receipts are a form of acknowledgement of an event. This module defines a single acknowledgement: m.read which indicates that the user has read up to a given event.
Sending a receipt for each event can result in sending large amounts of traffic to a homeserver. To prevent this from becoming a problem, receipts are implemented using "up to" markers. This marker indicates that the acknowledgement applies to all events "up to and including" the event specified. For example, marking an event as "read" would indicate that the user had read all events up to the referenced event. See the Receiving notifications section for more information on how read receipts affect notification counts.
Each user_id, receipt_type pair must be associated with only a single event_id.
Informs the client of new receipts.
Content Key | Type | Description |
---|---|---|
$EVENT_ID | 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. |
Receipts Key | Type | Description |
---|---|---|
m.read | Users | A collection of users who have sent m.read receipts for this event. |
Users Key | Type | Description |
---|---|---|
$USER_ID | Receipt | The mapping of user ID to receipt. The user ID is the entity who sent this receipt. |
Receipt Key | Type | Description |
---|---|---|
ts | number | The timestamp the receipt was sent at. |
Example:
{ "content": { "$1435641916114394fHBLK:matrix.org": { "m.read": { "@rikj:jki.re": { "ts": 1436451550453 } } } }, "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "type": "m.receipt" }
In /sync, receipts are listed under the ephemeral array of events for a given room. New receipts that come down the event streams are deltas which update existing mappings. Clients should replace older receipt acknowledgements based on user_id and receipt_type pairs. For example:
Client receives m.receipt: user = @alice:example.com receipt_type = m.read event_id = $aaa:example.com Client receives another m.receipt: user = @alice:example.com receipt_type = m.read event_id = $bbb:example.com The client should replace the older acknowledgement for $aaa:example.com with this one for $bbb:example.com
Clients should send read receipts when there is some certainty that the event in question has been displayed to the user. Simply receiving an event does not provide enough certainty that the user has seen the event. The user SHOULD need to take some action such as viewing the room that the event was sent to or dismissing a notification in order for the event to count as "read". Clients SHOULD NOT send read receipts for events sent by their own user.
A client can update the markers for its user by interacting with the following HTTP APIs.
This API updates the marker for the given receipt type to the event ID specified.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room in which to send the event. |
receiptType | enum | Required. The type of receipt to send. One of: ["m.read"] |
eventId | string | Required. The event ID to acknowledge up to. |
Example request:
POST /_matrix/client/r0/rooms/%21wefuh21ffskfuh345%3Aexample.com/receipt/m.read/%241924376522eioj%3Aexample.com HTTP/1.1 Content-Type: application/json {}
Responses:
Status code 200:
The receipt was sent.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
For efficiency, receipts SHOULD be batched into one event per room before delivering them to clients.
Receipts are sent across federation as EDUs with type m.receipt. The format of the EDUs are:
{ <room_id>: { <receipt_type>: { <user_id>: { <content> } }, ... }, ... }
These are always sent as deltas to previously sent receipts. Currently only a single <receipt_type> should be used: m.read.
As receipts are sent outside the context of the event graph, there are no integrity checks performed on the contents of m.receipt events.
The history for a given room may be split into three sections: messages the user has read (or indicated they aren't interested in them), messages the user might have read some but not others, and messages the user hasn't seen yet. The "fully read marker" (also known as a "read marker") marks the last event of the first section, whereas the user's read receipt marks the last event of the second section.
The user's fully read marker is kept as an event in the room's account data. The event may be read to determine the user's current fully read marker location in the room, and just like other account data events the event will be pushed down the event stream when updated.
The fully read marker is kept under an m.fully_read event. If the event does not exist on the user's account data, the fully read marker should be considered to be the user's read receipt location.
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.
Content Key | Type | Description |
---|---|---|
event_id | string | Required. The event the user's read marker is located at in the room. |
Example:
{ "content": { "event_id": "$someplace:example.org" }, "room_id": "!somewhere:example.org", "type": "m.fully_read" }
The client cannot update fully read markers by directly modifying the m.fully_read account data event. Instead, the client must make use of the read markers API to change the values.
The read markers API can additionally update the user's read receipt (m.read) location in the same operation as setting the fully read marker location. This is because read receipts and read markers are commonly updated at the same time, and therefore the client might wish to save an extra HTTP call. Providing an m.read location performs the same task as a request to /receipts/m.read/$event:example.org.
Sets the position of the read marker for a given room, and optionally the read receipt's location.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room ID to set the read marker in for the user. |
JSON body parameters | ||
m.fully_read | string | Required. The event ID the read marker should be located at. The event MUST belong to the room. |
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. |
Example request:
POST /_matrix/client/r0/rooms/%21somewhere%3Aexample.org/read_markers HTTP/1.1 Content-Type: application/json { "m.fully_read": "$somewhere:example.org", "m.read": "$elsewhere:example.org" }
Responses:
Status code 200:
The read marker, and read receipt if provided, have been updated.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
The server MUST prevent clients from setting m.fully_read directly in room account data. The server must additionally ensure that it treats the presence of m.read in the /read_markers request the same as how it would for a request to /receipts/m.read/$event:example.org.
Upon updating the m.fully_read event due to a request to /read_markers, the server MUST send the updated account data event through to the client via the event stream (eg: /sync), provided any applicable filters are also satisfied.
Each user has the concept of presence information. This encodes:
This information is collated from both per-device (online, idle, last_active) and per-user (status) data, aggregated by the user's homeserver and transmitted as an m.presence event. Presence events are sent to interested parties where users share a room membership.
User's presence state is represented by the presence key, which is an enum of one of the following:
Informs the client of a user's presence state change.
Content Key | Type | Description |
---|---|---|
avatar_url | string | The current avatar URL for this user, if any. |
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 | enum | Required. The presence state for this user. One of: ["online", "offline", "unavailable"] |
currently_active | boolean | Whether the user is currently active |
status_msg | string | An optional description to accompany the presence. |
Example:
{ "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" }
Clients can manually set/get their presence using the HTTP APIs listed below.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose presence state to update. |
JSON body parameters | ||
presence | enum | Required. The new presence state. One of: ["online", "offline", "unavailable"] |
status_msg | string | The status message to attach to this state. |
Example request:
PUT /_matrix/client/r0/presence/%40alice%3Aexample.com/status HTTP/1.1 Content-Type: application/json { "presence": "online", "status_msg": "I am here." }
Responses:
Status code 200:
The new presence state was set.
Example
{}
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Get the given user's presence state.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose presence state to get. |
Response format:
Parameter | Type | Description |
---|---|---|
presence | enum | Required. This user's presence. One of: ["online", "offline", "unavailable"] |
last_active_ago | integer | The length of time in milliseconds since an action was performed by this user. |
status_msg | string or null | The state message for this user if one was set. |
currently_active | boolean | Whether the user is currently active |
Example request:
GET /_matrix/client/r0/presence/%40alice%3Aexample.com/status HTTP/1.1
Responses:
Status code 200:
The presence state for this user.
Example
{ "presence": "unavailable", "last_active_ago": 420845 }
Status code 403:
You are not allowed to see this user's presence status.
Example
{ "errcode": "M_FORBIDDEN", "error": "You are not allowed to see their presence" }
Status code 404:
There is no presence state for this user. This user may not exist or isn't exposing presence information to you.
Example
{ "errcode": "M_UNKNOWN", "error": "An unknown error occurred" }
The server maintains a timestamp of the last time it saw a pro-active event from the user. A pro-active event may be sending a message to a room or changing presence state to online. This timestamp is presented via a key called last_active_ago which gives the relative number of milliseconds since the pro-active event.
To reduce the number of presence updates sent to clients the server may include a currently_active boolean field when the presence state is online. When true, the server will not send further updates to the last active time until an update is sent to the client with either a) currently_active set to false or b) a presence state other than online. During this period clients must consider the user to be currently active, irrespective of the last active time.
The last active time must be up to date whenever the server gives a presence event to the client. The currently_active mechanism should purely be used by servers to stop sending continuous presence updates, as opposed to disabling last active tracking entirely. Thus clients can fetch up to date last active times by explicitly requesting the presence for a given user.
The server will automatically set a user's presence to unavailable if their last active time was over a threshold value (e.g. 5 minutes). Clients can manually set a user's presence to unavailable. Any activity that bumps the last active time on any of the user's clients will cause the server to automatically set their presence to online.
Presence information is shared with all users who share a room with the target user. In large public rooms this could be undesirable.
The content repository (or "media repository") allows users to upload files to their homeserver for later user. For example, files which the user wants to send to a room would be uploaded here, as would an avatar the user wants to use.
Uploads are POSTed to a resource on the user's local homeserver which returns a MXC URI which can later be used to GET the download. Content is downloaded from the recipient's local homeserver, which must first transfer the content from the origin homeserver using the same API (unless the origin and destination homeservers are the same).
When serving content, the server SHOULD provide a Content-Security-Policy header. The recommended policy is sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';.
Content locations are represented as Matrix Content (MXC) URIs. They look like:
mxc://<server-name>/<media-id> <server-name> : The name of the homeserver where this content originated, e.g. matrix.org <media-id> : An opaque ID which identifies the content.
Clients can upload and download content using the following HTTP APIs.
Upload some content to the content repository.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
header parameters | ||
Content-Type | string | The content type of the file being uploaded |
query parameters | ||
filename | string | The name of the file being uploaded |
Response format:
Parameter | Type | Description |
---|---|---|
content_uri | string | Required. The MXC URI to the uploaded content. |
Example request:
POST /_matrix/media/r0/upload?filename=War+and+Peace.pdf HTTP/1.1 Content-Type: Content-Type: application/pdf <bytes>
Responses:
Status code 200:
The MXC URI for the uploaded content.
Example
{ "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" }
Status code 403:
The user does not have permission to upload the content. Some reasons for this error include:
Example
{ "errcode": "M_FORBIDDEN", "error": "Cannot upload this content" }
Status code 413:
The uploaded content is too large for the server.
Example
{ "errcode": "M_TOO_LARGE", "error": "Cannot upload files larger than 100mb" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Download content from the content repository.
Rate-limited: | Yes. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
serverName | string | Required. The server name from the mxc:// URI (the authoritory component) |
mediaId | string | Required. The media ID from the mxc:// URI (the path component) |
query parameters | ||
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. |
Response headers:
Parameter | Type | Description |
---|---|---|
Content-Type | string | The content type of the file that was previously uploaded. |
Content-Disposition | string | The name of the file that was previously uploaded, if set. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | file | Required. The bytes for the uploaded file. |
Example request:
GET /_matrix/media/r0/download/matrix.org/ascERGshawAWawugaAcauga?allow_remote=False HTTP/1.1
Responses:
Status code 200:
The content that was previously uploaded.
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Status code 502:
The content is too large for the server to serve.
Example
{ "errcode": "M_TOO_LARGE", "error": "Content is too large to serve" }
Download content from the content repository. This is the same as the download endpoint above, except permitting a desired file name.
Rate-limited: | Yes. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
serverName | string | Required. The server name from the mxc:// URI (the authoritory component) |
mediaId | string | Required. The media ID from the mxc:// URI (the path component) |
fileName | string | Required. A filename to give in the Content- Disposition header. |
query parameters | ||
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. |
Response headers:
Parameter | Type | Description |
---|---|---|
Content-Type | string | The content type of the file that was previously uploaded. |
Content-Disposition | string | The fileName requested or the name of the file that was previously uploaded, if set. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | file | Required. The bytes for the uploaded file. |
Example request:
GET /_matrix/media/r0/download/matrix.org/ascERGshawAWawugaAcauga/filename.jpg?allow_remote=False HTTP/1.1
Responses:
Status code 200:
The content that was previously uploaded.
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Status code 502:
The content is too large for the server to serve.
Example
{ "errcode": "M_TOO_LARGE", "error": "Content is too large to serve" }
Download a thumbnail of content from the content repository. See the thumbnailing section for more information.
Rate-limited: | Yes. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
serverName | string | Required. The server name from the mxc:// URI (the authoritory component) |
mediaId | string | Required. The media ID from the mxc:// URI (the path component) |
query parameters | ||
width | integer | Required. The desired width of the thumbnail. The actual thumbnail may be larger than the size specified. |
height | integer | Required. The desired height of the thumbnail. The actual thumbnail may be larger than the size specified. |
method | enum | The desired resizing method. See the thumbnailing section for more information. One of: ["crop", "scale"] |
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. |
Response headers:
Parameter | Type | Description |
---|---|---|
Content-Type | string | The content type of the thumbnail. |
Response format:
Parameter | Type | Description |
---|---|---|
<body> | file | Required. The bytes for the thumbnail. |
Example request:
GET /_matrix/media/r0/thumbnail/example.org/ascERGshawAWawugaAcauga?width=64&height=64&method=scale&allow_remote=False HTTP/1.1
Responses:
Status code 200:
A thumbnail of the requested content.
Status code 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.
Example
{ "errcode": "M_UNKNOWN", "error": "Cannot generate thumbnails for the requested content" }
Status code 413:
The local content is too large for the server to thumbnail.
Example
{ "errcode": "M_TOO_LARGE", "error": "Content is too large to thumbnail" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Status code 502:
The remote content is too large for the server to thumbnail.
Example
{ "errcode": "M_TOO_LARGE", "error": "Content is too large to thumbnail" }
Get information about a URL for a client
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
url | string | Required. The URL to get a preview of. |
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. |
Response format:
Parameter | Type | Description |
---|---|---|
matrix:image:size | integer | The byte-size of the image. Omitted if there is no image attached. |
og:image | string | An MXC URI to the image. Omitted if there is no image. |
Example request:
GET /_matrix/media/r0/preview_url?url=https%3A%2F%2Fmatrix.org&ts=1510610716656 HTTP/1.1
Responses:
Status code 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.
Example
{ "og:title": "Matrix Blog Post", "og:description": "This is a really cool blog post from matrix.org", "og:image": "mxc://example.com/ascERGshawAWawugaAcauga", "og:image:type": "image/png", "og:image:height": 48, "og:image:width": 48, "matrix:image:size": 102400 }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
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 auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | 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. |
Example request:
GET /_matrix/media/r0/config HTTP/1.1
Responses:
Status code 200:
The public content repository configuration for the matrix server.
Example
{ "m.upload.size": 50000000 }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_UNKNOWN", "error": "An unknown error occurred" }
The homeserver SHOULD be able to supply thumbnails for uploaded images and videos. The exact file types which can be thumbnailed are not currently specified - see Issue #1938 for more information.
The thumbnail methods are "crop" and "scale". "scale" tries to return an image where either the width or the height is smaller than the requested size. The client should then scale and letterbox the image if it needs to fit within a given rectangle. "crop" tries to return an image where the width and height are close to the requested size and the aspect matches the requested size. The client should scale the image if it needs to fit within a given rectangle.
The dimensions given to the thumbnail API are the minimum size the client would prefer. Servers must never return thumbnails smaller than the client's requested dimensions, unless the content being thumbnailed is smaller than the dimensions. When the content is smaller than the requested dimensions, servers should return the original content rather than thumbnail it.
Servers SHOULD produce thumbnails with the following dimensions and methods:
Servers MUST NOT upscale thumbnails under any circumstance. Servers MUST NOT return a smaller thumbnail than requested, unless the original content makes that impossible.
The HTTP GET endpoint does not require any authentication. Knowing the URL of the content is sufficient to retrieve the content, even if the entity isn't in the room.
MXC URIs are vulnerable to directory traversal attacks such as mxc://127.0.0.1/../../../some_service/etc/passwd. This would cause the target homeserver to try to access and return this file. As such, homeservers MUST sanitise MXC URIs by allowing only alphanumeric (A-Za-z0-9), _ and - characters in the server-name and media-id values. This set of whitelisted characters allows URL-safe base64 encodings specified in RFC 4648. Applying this character whitelist is preferable to blacklisting . and / as there are techniques around blacklisted characters (percent-encoded characters, UTF-8 encoded traversals, etc).
Homeservers have additional content-specific concerns:
This module provides a means by which clients can exchange signalling messages without them being stored permanently as part of a shared communication history. A message is delivered exactly once to each client device.
The primary motivation for this API is exchanging data that is meaningless or undesirable to persist in the room DAG - for example, one-time authentication tokens or key data. It is not intended for conversational data, which should be sent using the normal /rooms/<room_id>/send API for consistency throughout Matrix.
To send a message to other devices, a client should call /sendToDevice. Only one message can be sent to each device per transaction, and they must all have the same event type. The device ID in the request body can be set to * to request that the message be sent to all known devices.
If there are send-to-device messages waiting for a client, they will be returned by /sync, as detailed in Extensions to /sync. Clients should inspect the type of each returned event, and ignore any they do not understand.
Servers should store pending messages for local users until they are successfully delivered to the destination device. When a client calls /sync with an access token which corresponds to a device with pending messages, the server should list the pending messages, in order of arrival, in the response body.
When the client calls /sync again with the next_batch token from the first response, the server should infer that any send-to-device messages in that response have been delivered successfully, and delete them from the store.
If there is a large queue of send-to-device messages, the server should limit the number sent in each /sync response. 100 messages is recommended as a reasonable limit.
If the client sends messages to users on remote domains, those messages should be sent on to the remote servers via federation.
This endpoint is used to send send-to-device events to a set of client devices.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
JSON body parameters | ||
messages | {string: {string: EventContent}} | 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. |
Example request:
PUT /_matrix/client/r0/sendToDevice/m.new_device/35 HTTP/1.1 Content-Type: application/json { "messages": { "@alice:example.com": { "TLLBEANAAG": { "example_content_key": "value" } } } }
Response:
Status code 200:
The message was successfully sent.
Example
{}
This module adds the following properties to the /sync response:
Parameter | Type | Description |
---|---|---|
to_device | ToDevice | Optional. Information on the send-to-device messages for the client device. |
ToDevice
Parameter | Type | Description |
---|---|---|
events | [Event] | List of send-to-device messages. |
Event
Parameter | Type | Description |
---|---|---|
content | EventContent | The content of this event. The fields in this object will vary depending on the type of event. |
sender | string | The Matrix user ID of the user who sent this event. |
type | string | The type of event. |
Example response:
{ "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"] } } ] } }
This module provides a means for a user to manage their devices.
Clients that implement this module should offer the user a list of registered devices, as well as the means to update their display names. Clients should also allow users to delete disused devices.
Gets information about all devices for the current user.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
devices | [Device] | A list of all registered devices for this user. |
Parameter | 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). |
Example request:
GET /_matrix/client/r0/devices HTTP/1.1
Response:
Status code 200:
Device information
Example
{ "devices": [ { "device_id": "QBUAZIFURK", "display_name": "android", "last_seen_ip": "1.2.3.4", "last_seen_ts": 1474491775024 } ] }
Gets information on a single device, by device id.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
deviceId | string | Required. The device to retrieve. |
Response format:
Parameter | 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). |
Example request:
GET /_matrix/client/r0/devices/QBUAZIFURK HTTP/1.1
Responses:
Status code 200:
Device information
Example
{ "device_id": "QBUAZIFURK", "display_name": "android", "last_seen_ip": "1.2.3.4", "last_seen_ts": 1474491775024 }
Status code 404:
The current user has no device with the given ID.
Updates the metadata on the given device.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
deviceId | string | Required. The device to update. |
JSON body parameters | ||
display_name | string | The new display name for this device. If not given, the display name is unchanged. |
Example request:
PUT /_matrix/client/r0/devices/QBUAZIFURK HTTP/1.1 Content-Type: application/json { "display_name": "My other phone" }
Responses:
Status code 200:
The device was successfully updated.
Example
{}
Status code 404:
The current user has no device with the given ID.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
deviceId | string | Required. The device to delete. |
JSON body parameters | ||
auth | Authentication Data | Additional authentication information for the user-interactive authentication API. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The login type that the client is attempting to complete. |
session | string | The value of the session key given by the homeserver. |
Example request:
DELETE /_matrix/client/r0/devices/QBUAZIFURK HTTP/1.1 Content-Type: application/json { "auth": { "type": "example.type.foo", "session": "xxxxx", "example_credential": "verypoorsharedsecret" } }
Responses:
Status code 200:
The device was successfully removed, or had been removed previously.
Example
{}
Status code 401:
The homeserver requires additional authentication information.
Example
{ "flows": [ { "stages": [ "example.type.foo" ] } ], "params": { "example.type.baz": { "example_key": "foobar" } }, "session": "xxxxxxyz", "completed": [ "example.type.foo" ] }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
devices | [string] | Required. The list of device IDs to delete. |
auth | Authentication Data | Additional authentication information for the user-interactive authentication API. |
Parameter | Type | Description |
---|---|---|
type | string | Required. The login type that the client is attempting to complete. |
session | string | The value of the session key given by the homeserver. |
Example request:
POST /_matrix/client/r0/delete_devices HTTP/1.1 Content-Type: application/json { "devices": [ "QBUAZIFURK", "AUIECTSRND" ], "auth": { "type": "example.type.foo", "session": "xxxxx", "example_credential": "verypoorsharedsecret" } }
Responses:
Status code 200:
The devices were successfully removed, or had been removed previously.
Example
{}
Status code 401:
The homeserver requires additional authentication information.
Example
{ "flows": [ { "stages": [ "example.type.foo" ] } ], "params": { "example.type.baz": { "example_key": "foobar" } }, "session": "xxxxxxyz", "completed": [ "example.type.foo" ] }
Deleting devices has security implications: it invalidates the access_token assigned to the device, so an attacker could use it to log out the real user (and do it repeatedly every time the real user tries to log in to block the attacker). Servers should require additional authentication beyond the access token when deleting devices (for example, requiring that the user resubmit their password).
The display names of devices are publicly visible. Clients should consider advising the user of this.
Matrix optionally supports end-to-end encryption, allowing rooms to be created whose conversation contents are not decryptable or interceptable on any of the participating homeservers.
Encryption and Authentication in Matrix is based around public-key cryptography. The Matrix protocol provides a basic mechanism for exchange of public keys, though an out-of-band channel is required to exchange fingerprints between users to build a web of trust.
1) Bob publishes the public keys and supported algorithms for his device. This may include long-term identity keys, and/or one-time keys. +----------+ +--------------+ | Bob's HS | | Bob's Device | +----------+ +--------------+ | | |<=============| /keys/upload 2) Alice requests Bob's public identity keys and supported algorithms. +----------------+ +------------+ +----------+ | Alice's Device | | Alice's HS | | Bob's HS | +----------------+ +------------+ +----------+ | | | |=================>|==============>| /keys/query <federation> 3) Alice selects an algorithm and claims any one-time keys needed. +----------------+ +------------+ +----------+ | Alice's Device | | Alice's HS | | Bob's HS | +----------------+ +------------+ +----------+ | | | |=================>|==============>| /keys/claim <federation>
The name ed25519 corresponds to the Ed25519 signature algorithm. The key is a 32-byte Ed25519 public key, encoded using unpadded Base64. Example:
"SogYyrkTldLz0BXP+GYWs0qaYacUI0RleEqNT8J3riQ"
The name curve25519 corresponds to the Curve25519 ECDH algorithm. The key is a 32-byte Curve25519 public key, encoded using unpadded Base64. Example:
"JGLn/yafz74HB2AbPLYJWIVGnKAtqECOBf11yyXac2Y"
The name signed_curve25519 also corresponds to the Curve25519 algorithm, but keys using this algorithm are objects with the properties key (giving the Base64-encoded 32-byte Curve25519 public key), and signatures (giving a signature for the key object, as described in Signing JSON). Example:
{ "key":"06UzBknVHFMwgi7AVloY7ylC+xhOhEX4PkNge14Grl8", "signatures": { "@user:example.com": { "ed25519:EGURVBUNJP": "YbJva03ihSj5mPk+CHMJKUKlCXCPFXjXOK6VqBnN9nA2evksQcTGn6hwQfrgRHIDDXO2le49x7jnWJHMJrJoBQ" } } }
Each device should have one Ed25519 signing key. This key should be generated on the device from a cryptographically secure source, and the private part of the key should never be exported from the device. This key is used as the fingerprint for a device by other clients.
A device will generally need to generate a number of additional keys. Details of these will vary depending on the messaging algorithm in use.
Algorithms generally require device identity keys as well as signing keys. Some algorithms also require one-time keys to improve their secrecy and deniability. These keys are used once during session establishment, and are then thrown away.
For Olm version 1, each device requires a single Curve25519 identity key, and a number of signed Curve25519 one-time keys.
A device uploads the public parts of identity keys to their homeserver as a signed JSON object, using the /keys/upload API. The JSON object must include the public part of the device's Ed25519 key, and must be signed by that key, as described in Signing JSON.
One-time keys are also uploaded to the homeserver using the /keys/upload API.
Devices must store the private part of each key they upload. They can discard the private part of a one-time key when they receive a message using that key. However it's possible that a one-time key given out by a homeserver will never be used, so the device that generates the key will never know that it can discard the key. Therefore a device could end up trying to store too many private keys. A device that is trying to store too many private keys may discard keys starting with the oldest.
Before Alice can send an encrypted message to Bob, she needs a list of each of his devices and the associated identity keys, so that she can establish an encryption session with each device. This list can be obtained by calling /keys/query, passing Bob's user ID in the device_keys parameter.
From time to time, Bob may add new devices, and Alice will need to know this so that she can include his new devices for later encrypted messages. A naive solution to this would be to call /keys/query before sending each message - however, the number of users and devices may be large and this would be inefficient.
It is therefore expected that each client will maintain a list of devices for a number of users (in practice, typically each user with whom we share an encrypted room). Furthermore, it is likely that this list will need to be persisted between invocations of the client application (to preserve device verification data and to alert Alice if Bob suddenly gets a new device).
Alice's client can maintain a list of Bob's devices via the following process:
Warning
Bob may update one of his devices while Alice has a request to /keys/query in flight. Alice's client may therefore see Bob's user ID in the device_lists field of the /sync response while the first request is in flight, and initiate a second request to /keys/query. This may lead to either of two related problems.
The first problem is that, when the first request completes, the client will clear the 'outdated' flag for Bob's devices. If the second request fails, or the client is shut down before it completes, this could lead to Alice using an outdated list of Bob's devices.
The second possibility is that, under certain conditions, the second request may complete before the first one. When the first request completes, the client could overwrite the later results from the second request with those from the first request.
Clients MUST guard against these situations. For example, a client could ensure that only one request to /keys/query is in flight at a time for each user, by queuing additional requests until the first completes. Alternatively, the client could make a new request immediately, but ensure that the first request's results are ignored (possibly by cancelling the request).
Note
When Bob and Alice share a room, with Bob tracking Alice's devices, she may leave the room and then add a new device. Bob will not be notified of this change, as he doesn't share a room anymore with Alice. When they start sharing a room again, Bob has an out-of-date list of Alice's devices. In order to address this issue, Bob's homeserver will add Alice's user ID to the changed property of the device_lists field, thus Bob will update his list of Alice's devices as part of his normal processing. Note that Bob can also be notified when he stops sharing any room with Alice by inspecting the left property of the device_lists field, and as a result should remove her from its list of tracked users.
When encryption is enabled in a room, files should be uploaded encrypted on the homeserver.
In order to achieve this, a client should generate a single-use 256-bit AES key, and encrypt the file using AES-CTR. The counter should be 64-bit long, starting at 0 and prefixed by a random 64-bit Initialization Vector (IV), which together form a 128-bit unique counter block.
Warning
An IV must never be used multiple times with the same key. This implies that if there are multiple files to encrypt in the same message, typically an image and its thumbnail, the files must not share both the same key and IV.
Then, the encrypted file can be uploaded to the homeserver. The key and the IV must be included in the room event along with the resulting mxc:// in order to allow recipients to decrypt the file. As the event containing those will be Megolm encrypted, the server will never have access to the decrypted file.
A hash of the ciphertext must also be included, in order to prevent the homeserver from changing the file content.
A client should send the data as an encrypted m.room.message event, using either m.file as the msgtype, or the appropriate msgtype for the file type. The key is sent using the JSON Web Key format, with a W3C extension.
This module adds file and thumbnail_file properties, of type EncryptedFile, to m.message msgtypes that reference files, such as m.file and m.image, replacing the url and thumbnail_url properties.
EncryptedFile
Parameter | Type | Description |
---|---|---|
url | string | Required. The URL to the file. |
key | JWK | Required. A JSON Web Key object. |
iv | string | Required. The Initialisation Vector used by AES-CTR, encoded as unpadded base64. |
hashes | {string: string} | Required. A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64. Clients should support the SHA-256 hash, which uses the key sha256. |
v | string | Required. Version of the encrypted attachments protocol. Must be v2. |
JWK
Parameter | Type | Description |
---|---|---|
kty | string | Required. Key type. Must be oct. |
key_ops | [string] | Required. Key operations. Must at least contain encrypt and decrypt. |
alg | string | Required. Algorithm. Must be A256CTR. |
k | string | Required. The key, encoded as urlsafe unpadded base64. |
ext | boolean | Required. Extractable. Must be true. This is a W3C extension. |
Example:
{ "content": { "body": "something-important.jpg", "file": { "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe", "mimetype": "image/jpeg", "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" }, "mimetype": "image/jpeg", "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 } }
A client wanting to set up a session with another device can claim a one-time key for that device. This is done by making a request to the /keys/claim API.
A homeserver should rate-limit the number of one-time keys that a given user or remote server can claim. A homeserver should discard the public part of a one time key once it has given that key to another user.
Before Alice sends Bob encrypted data, or trusts data received from him, she may want to verify that she is actually communicating with him, rather than a man-in-the-middle. This verification process requires an out-of-band channel: there is no way to do it within Matrix without trusting the administrators of the homeservers.
In Matrix, verification works by Alice meeting Bob in person, or contacting him via some other trusted medium, and use SAS Verification to interactively verify Bob's devices. Alice and Bob may also read aloud their unpadded base64 encoded Ed25519 public key, as returned by /keys/query.
Device verification may reach one of several conclusions. For example:
Note
Once the signing key has been verified, it is then up to the encryption protocol to verify that a given message was sent from a device holding that Ed25519 private key, or to encrypt a message so that it may only be decrypted by such a device. For the Olm protocol, this is documented at https://matrix.org/git/olm/about/docs/signing.rst.
Verifying keys manually by reading out the Ed25519 key is not very user friendly, and can lead to errors. In order to help mitigate errors, and to make the process eaiser for users, some verification methods are supported by the specification. The methods all use a common framework for negotiating the key verification.
To use this framework, Alice's client would send m.key.verification.request events to Bob's devices. All of the to_device messages sent to Bob MUST have the same transaction_id to indicate they are part of the same request. This allows Bob to reject the request on one device, and have it apply to all of his devices. Similarly, it allows Bob to process the verification on one device without having to involve all of his devices.
When Bob's device receives a m.key.verification.request, it should prompt Bob to verify keys with Alice using one of the supported methods in the request. If Bob's device does not understand any of the methods, it should not cancel the request as one of his other devices may support the request. Instead, Bob's device should tell Bob that an unsupported method was used for starting key verification. The prompt for Bob to accept/reject Alice's request (or the unsupported method prompt) should be automatically dismissed 10 minutes after the timestamp field or 2 minutes after Bob's client receives the message, whichever comes first, if Bob does not interact with the prompt. The prompt should additionally be hidden if an appropriate m.key.verification.cancel message is received.
If Bob rejects the request, Bob's client must send a m.key.verification.cancel message to Alice's device. Upon receipt, Alice's device should tell her that Bob does not want to verify her device and send m.key.verification.cancel messages to all of Bob's devices to notify them that the request was rejected.
If Bob accepts the request, Bob's device starts the key verification process by sending a m.key.verification.start message to Alice's device. Upon receipt of this message, Alice's device should send a m.key.verification.cancel message to all of Bob's other devices to indicate the process has been started. The start message must use the same transaction_id from the original key verification request if it is in response to the request. The start message can be sent indepdently of any request.
Individual verification methods may add additional steps, events, and properties to the verification messages. Event types for methods defined in this specification must be under the m.key.verification namespace and any other event types must be namespaced according to the Java package naming convention.
Any of Alice's or Bob's devices can cancel the key verification request or process at any time with a m.key.verification.cancel message to all applicable devices.
This framework yields the following handshake, assuming both Alice and Bob each have 2 devices, Bob's first device accepts the key verification request, and Alice's second device initiates the request. Note how Alice's first device is not involved in the request or verification process.
+---------------+ +---------------+ +-------------+ +-------------+ | AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 | +---------------+ +---------------+ +-------------+ +-------------+ | | | | | | m.key.verification.request | | | |---------------------------------->| | | | | | | | m.key.verification.request | | | |-------------------------------------------------->| | | | | | | m.key.verification.start | | | |<----------------------------------| | | | | | | | m.key.verification.cancel | | | |-------------------------------------------------->| | | | |
After the handshake, the verification process begins.
Requests a key verification with another user's devices. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
from_device | string | Required. The device ID which is initiating the request. |
transaction_id | string | Required. An opaque identifier for the verification request. Must be unique with respect to the devices involved. |
methods | [string] | Required. The verification methods supported by the sender. |
timestamp | integer | Required. 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. |
Example:
{ "content": { "from_device": "AliceDevice2", "methods": [ "m.sas.v1" ], "timestamp": 1559598944869, "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.request" }
Begins a key verification process. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
from_device | string | Required. The device ID which is initiating the process. |
transaction_id | string | Required. 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. |
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. |
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" ], "method": "m.sas.v1", "short_authentication_string": [ "decimal", "emoji" ], "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.start" }
Cancels a key verification process/request. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
transaction_id | string | Required. The opaque identifier for the verification process/request. |
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. |
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. |
Example:
{ "content": { "code": "m.user", "reason": "User rejected the key verification request", "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.cancel" }
SAS verification is a user-friendly key verification process built off the common framework outlined above. SAS verification is intended to be a highly interactive process for users, and as such exposes verfiication methods which are easier for users to use.
The verification process is heavily inspired by Phil Zimmerman's ZRTP key agreement handshake. A key part of key agreement in ZRTP is the hash commitment: the party that begins the Diffie-Hellman key sharing sends a hash of their part of the Diffie-Hellman exchange, and does not send their part of the Diffie-Hellman exchange until they have received the other party's part. Thus an attacker essentially only has one attempt to attack the Diffie-Hellman exchange, and hence we can verify fewer bits while still achieving a high degree of security: if we verify n bits, then an attacker has a 1 in 2n chance of success. For example, if we verify 40 bits, then an attacker has a 1 in 1,099,511,627,776 chance (or less than 1 in 1012 chance) of success. A failed attack would result in a mismatched Short Authentication String, alerting users to the attack.
The verification process takes place over to-device messages in two phases:
The process between Alice and Bob verifying each other would be:
The wire protocol looks like the following between Alice and Bob's devices:
+-------------+ +-----------+ | 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 | |<--------------------------------| | |
At any point the interactive verfication can go wrong. The following describes what to do when an error happens:
Building off the common framework, the following events are involved in SAS verification.
The m.key.verification.cancel event is unchanged, however the following error codes are used in addition to those already specified:
Begins a SAS key verification process. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
from_device | string | Required. The device ID which is initiating the process. |
transaction_id | string | Required. 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. |
method | string | Required. The verification method to use. Must be m.sas.v1. Must be 'm.sas.v1'. |
key_agreement_protocols | [string] | Required. The key agreement protocols the sending device understands. Must include at least curve25519. |
hashes | [string] | Required. The hash methods the sending device understands. Must include at least sha256. |
message_authentication_codes | [string] | Required. The message authentication codes that the sending device understands. Must include at least hkdf-hmac-sha256. |
short_authentication_string | [enum] | Required. The SAS methods the sending device (and the sending device's user) understands. Must include at least decimal. Optionally can include emoji. One of: ["decimal", "emoji"] |
Example:
{ "content": { "from_device": "BobDevice1", "hashes": [ "sha256" ], "key_agreement_protocols": [ "curve25519" ], "message_authentication_codes": [ "hkdf-hmac-sha256" ], "method": "m.sas.v1", "short_authentication_string": [ "decimal", "emoji" ], "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.start" }
Accepts a previously sent m.key.verification.start messge. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
transaction_id | string | Required. An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message. |
method | string | Required. The verification method to use. Must be 'm.sas.v1'. |
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. |
hash | string | Required. The hash method the device is choosing to use, out of the options in the m.key.verification.start message. |
message_authentication_code | string | Required. The message authentication code the device is choosing to use, out of the options in the m.key.verification.start message. |
short_authentication_string | [enum] | 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. One of: ["decimal", "emoji"] |
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. |
Example:
{ "content": { "commitment": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg", "hash": "sha256", "key_agreement_protocol": "curve25519", "message_authentication_code": "hkdf-hmac-sha256", "method": "m.sas.v1", "short_authentication_string": [ "decimal", "emoji" ], "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.accept" }
Sends the ephemeral public key for a device to the partner device. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
transaction_id | string | Required. An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message. |
key | string | Required. The device's ephemeral public key, encoded as unpadded base64. |
Example:
{ "content": { "key": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg", "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.key" }
Sends the MAC of a device's key to the partner device. Typically sent as a to-device event.
Content Key | Type | Description |
---|---|---|
transaction_id | string | Required. An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message. |
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. |
keys | string | Required. The MAC of the comma-separated, sorted, list of key IDs given in the mac property, encoded as unpadded base64. |
Example:
{ "content": { "keys": "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA", "mac": { "ed25519:ABCDEF": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" }, "transaction_id": "S0meUniqueAndOpaqueString" }, "type": "m.key.verification.mac" }
In all of the SAS methods, HKDF is as defined in [RFC 5869](https://tools.ietf.org/html/rfc5869) and uses the previously agreed-upon hash function for the hash function. The shared secret is supplied as the input keying material. No salt is used, and the input parameter is the concatenation of:
- The string MATRIX_KEY_VERIFICATION_SAS.
- The Matrix ID of the user who sent the m.key.verification.start message.
- The Device ID of the device which sent the m.key.verification.start message.
- The Matrix ID of the user who sent the m.key.verification.accept message.
- The Device ID of the device which sent the m.key.verification.accept message.
- The transaction_id being used.
Rationale
HKDF is used over the plain shared secret as it results in a harder attack as well as more uniform data to work with.
For verification of each party's device keys, HKDF is as defined in RFC 5869 and uses SHA-256 as the hash function. The shared secret is supplied as the input keying material. No salt is used, and in the input parameter is the concatenation of:
- The string MATRIX_KEY_VERIFICATION_MAC.
- The Matrix ID of the user whose key is being MAC-ed.
- The Device ID of the device sending the MAC.
- The Matrix ID of the other user.
- The Device ID of the device receiving the MAC.
- The transaction_id being used.
- The Key ID of the key being MAC-ed, or the string KEY_IDS if the item being MAC-ed is the list of key IDs.
Generate 5 bytes using HKDF then take sequences of 13 bits to convert to decimal numbers (resulting in 3 numbers between 0 and 8191 inclusive each). Add 1000 to each calculated number.
The bitwise operations to get the numbers given the 5 bytes B0, B1, B2, B3, B4 would be:
The digits are displayed to the user either with an appropriate separator, such as dashes, or with the numbers on individual lines.
Generate 6 bytes using HKDF then split the first 42 bits into 7 groups of 6 bits, similar to how one would base64 encode something. Convert each group of 6 bits to a number and use the following table to get the corresponding emoji:
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 |
Note
This table is available as JSON at https://github.com/matrix-org/matrix-doc/blob/master/data-definitions/sas-emoji.json
Rationale
The emoji above were chosen to:
Clients SHOULD show the emoji with the descriptions from the table, or appropriate translation of those descriptions. Client authors SHOULD collaborate to create a common set of translations for all languages.
If Bob has an encrypted conversation with Alice on his computer, and then logs in through his phone for the first time, he may want to have access to the previously exchanged messages. To address this issue, several methods are provided to allow users to transfer keys from one device to another.
When a device is missing keys to decrypt messages, it can request the keys by sending m.room_key_request to-device messages to other devices with action set to request. If a device wishes to share the keys with that device, it can forward the keys to the first device by sending an encrypted m.forwarded_room_key to-device message. The first device should then send an m.room_key_request to-device message with action set to cancel_request to the other devices that it had originally sent the key request to; a device that receives a cancel_request should disregard any previously-received request message with the same request_id and requesting_device_id.
Note
Key sharing can be a big attack vector, thus it must be done very carefully. A reasonable strategy is for a user's client to only send keys requested by the verified devices of the same user.
Keys can be manually exported from one device to an encrypted file, copied to another device, and imported. The file is encrypted using a user-supplied passphrase, and is created as follows:
Encode the sessions as a JSON object, formatted as described in Key export format.
Generate a 512-bit key from the user-entered passphrase by computing PBKDF2(HMAC-SHA-512, passphrase, S, N, 512), where S is a 128-bit cryptographically-random salt and N is the number of rounds. N should be at least 100,000. The keys K and K' are set to the first and last 256 bits of this generated key, respectively. K is used as an AES-256 key, and K' is used as an HMAC-SHA-256 key.
Serialize the JSON object as a UTF-8 string, and encrypt it using AES-CTR-256 with the key K generated above, and with a 128-bit cryptographically-random initialization vector, IV, that has bit 63 set to zero. (Setting bit 63 to zero in IV is needed to work around differences in implementations of AES-CTR.)
Concatenate the following data:
Size (bytes) | Description |
---|---|
1 | Export format version, which must be 0x01. |
16 | The salt S. |
16 | The initialization vector IV. |
4 | The number of rounds N, as a big-endian unsigned 32-bit integer. |
variable | The encrypted JSON object. |
32 | The HMAC-SHA-256 of all the above string concatenated together, using K' as the key. |
Base64-encode the string above. Newlines may be added to avoid overly long lines.
Prepend the resulting string with -----BEGIN MEGOLM SESSION DATA-----, with a trailing newline, and append -----END MEGOLM SESSION DATA-----, with a leading and trailing newline.
The exported sessions are formatted as a JSON array of SessionData objects described as follows:
SessionData
Parameter | Type | Description |
---|---|---|
algorithm | string | Required. The encryption algorithm that the session uses. 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_key | string | Required. The Curve25519 key of the device which initiated the session originally. |
sender_claimed_keys | {string: string} | Required. The Ed25519 key of the device which initiated the session originally. |
session_id | string | Required. The ID of the session. |
session_key | string | Required. The key for the session. |
Example:
{ "sessions": [ { "algorithm": "m.megolm.v1.aes-sha2", "forwarding_curve25519_key_chain": [ "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw" ], "room_id": "!Cuyf34gef24t:localhost", "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU", "sender_claimed_keys": { "ed25519": "<device ed25519 identity key>", }, "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ", "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..." }, ... ] }
Messaging algorithm names use the extensible naming scheme used throughout this specification. Algorithm names that start with m. are reserved for algorithms defined by this specification. Implementations wanting to experiment with new algorithms must be uniquely globally namespaced following Java's package naming conventions.
Algorithm names should be short and meaningful, and should list the primitives used by the algorithm so that it is easier to see if the algorithm is using a broken primitive.
A name of m.olm.v1 is too short: it gives no information about the primitives in use, and is difficult to extend for different primitives. However a name of m.olm.v1.ecdh-curve25519-hdkfsha256.hmacsha256.hkdfsha256-aes256-cbc-hmac64sha256 is too long despite giving a more precise description of the algorithm: it adds to the data transfer overhead and sacrifices clarity for human readers without adding any useful extra information.
The name m.olm.v1.curve25519-aes-sha2 corresponds to version 1 of the Olm ratchet, as defined by the Olm specification. This uses:
Devices that support Olm must include "m.olm.v1.curve25519-aes-sha2" in their list of supported messaging algorithms, must list a Curve25519 device key, and must publish Curve25519 one-time keys.
An event encrypted using Olm has the following format:
{ "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 is a mapping from device Curve25519 key to an encrypted payload for that device. body is a Base64-encoded Olm message body. type is an integer indicating the type of the message body: 0 for the initial pre-key message, 1 for ordinary messages.
Olm sessions will generate messages with a type of 0 until they receive a message. Once a session has decrypted a message it will produce messages with a type of 1.
When a client receives a message with a type of 0 it must first check if it already has a matching session. If it does then it will use that session to try to decrypt the message. If there is no existing session then the client must create a new session and use the new session to decrypt the message. A client must not persist a session or remove one-time keys used by a session until it has successfully decrypted a message using that session.
Messages with type 1 can only be decrypted with an existing session. If there is no matching session, the client must treat this as an invalid message.
The plaintext payload is of the form:
{ "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>" } }
The type and content of the plaintext message event are given in the payload.
Other properties are included in order to prevent an attacker from publishing someone else's curve25519 keys as their own and subsequently claiming to have sent messages which they didn't. sender must correspond to the user who sent the event, recipient to the local user, and recipient_keys to the local ed25519 key.
Clients must confirm that the sender_key and the ed25519 field value under the keys property match the keys returned by /keys/query for the given user, and must also verify the signature of the payload. Without this check, a client cannot be sure that the sender device owns the private part of the ed25519 key it claims to have in the Olm payload. This is crucial when the ed25519 key corresponds to a verified device.
If a client has multiple sessions established with another device, it should use the session from which it last received and successfully decrypted a message. For these purposes, a session that has not received any messages should use its creation time as the time that it last received a message. A client may expire old sessions by defining a maximum number of olm sessions that it will maintain for each device, and expiring sessions on a Least Recently Used basis. The maximum number of olm sessions maintained per device should be at least 4.
Occasionally messages may be undecryptable by clients due to a variety of reasons. When this happens to an Olm-encrypted message, the client should assume that the Olm session has become corrupted and create a new one to replace it.
Note
Megolm-encrypted messages generally do not have the same problem. Usually the key for an undecryptable Megolm-encrypted message will come later, allowing the client to decrypt it successfully. Olm does not have a way to recover from the failure, making this session replacement process required.
To establish a new session, the client sends a m.dummy to-device event to the other party to notify them of the new session details.
Clients should rate-limit the number of sessions it creates per device that it receives a message from. Clients should not create a new session with another device if it has already created one for that given device in the past 1 hour.
Clients should attempt to mitigate loss of the undecryptable messages. For example, Megolm sessions that were sent using the old session would have been lost. The client can attempt to retrieve the lost sessions through m.room_key_request messages.
The name m.megolm.v1.aes-sha2 corresponds to version 1 of the Megolm ratchet, as defined by the Megolm specification. This uses:
Devices that support Megolm must support Olm, and include "m.megolm.v1.aes-sha2" in their list of supported messaging algorithms.
An event encrypted using Megolm has the following format:
{ "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>" } }
The encrypted payload can contain any message event. The plaintext is of the form:
{ "type": "<event_type>", "content": "<event_content>", "room_id": "<the room_id>" }
We include the room ID in the payload, because otherwise the homeserver would be able to change the room a message was sent in.
Clients must guard against replay attacks by keeping track of the ratchet indices of Megolm sessions. They should reject messages with a ratchet index that they have already decrypted. Care should be taken in order to avoid false positives, as a client may decrypt the same event twice as part of its normal processing.
As with Olm events, clients must confirm that the sender_key belongs to the user who sent the message. The same reasoning applies, but the sender ed25519 key has to be inferred from the keys.ed25519 property of the event which established the Megolm session.
In order to enable end-to-end encryption in a room, clients can send a m.room.encryption state event specifying m.megolm.v1.aes-sha2 as its algorithm property.
When creating a Megolm session in a room, clients must share the corresponding session key using Olm with the intended recipients, so that they can decrypt future messages encrypted using this session. A m.room_key event is used to do this. Clients must also handle m.room_key events sent by other devices in order to decrypt their messages.
Defines how messages sent in this room should be encrypted.
Content Key | Type | Description |
---|---|---|
algorithm | string | Required. The encryption algorithm to be used to encrypt messages sent in this room. Must be '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. |
Example:
{ "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 } }
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 Room Event fields), or as a to-device event.
Content Key | Type | Description |
---|---|---|
algorithm | enum | 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 or {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. |
sender_key | string | Required. The Curve25519 key of the sender. |
device_id | string | The ID of the sending device. Required with Megolm. |
session_id | string | The ID of the session used to encrypt the message. Required with Megolm. |
CiphertextInfo Key | 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 } }
{ "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 } }
This event type is used to exchange keys for end-to-end encryption. Typically it is encrypted as an m.room.encrypted event, then sent as a to-device event.
Content Key | Type | Description |
---|---|---|
algorithm | string | Required. The encryption algorithm the key in this event is to be used with. Must be '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. |
Example:
{ "content": { "algorithm": "m.megolm.v1.aes-sha2", "room_id": "!Cuyf34gef24t:localhost", "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ", "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8LlfJL7qNBEY..." }, "type": "m.room_key" }
This event type is used to request keys for end-to-end encryption. It is sent as an unencrypted to-device event.
Content Key | Type | Description |
---|---|---|
body | RequestedKeyInfo | Information about the requested key. Required when action is request. |
action | enum | Required. One of: ["request", "cancel_request"] |
requesting_device_id | string | Required. ID of the device requesting the key. |
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. |
RequestedKeyInfo Key | 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 | 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. |
Examples:
{ "content": { "action": "cancel_request", "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" }
This event type is used to forward keys for end-to-end encryption. Typically it is encrypted as an m.room.encrypted event, then sent as a to-device event.
Content Key | Type | Description |
---|---|---|
algorithm | string | Required. The encryption algorithm the key in this event is to be used with. |
room_id | string | Required. The room where the key is used. |
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. |
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. |
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. |
Example:
{ "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" }
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.
Example:
{ "content": {}, "type": "m.dummy" }
Publishes end-to-end encryption keys for the device.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
device_keys | DeviceKeys | Identity keys for the device. May be absent if no new identity keys are required. |
one_time_keys | {string: string or object} | 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. |
Parameter | Type | Description |
---|---|---|
user_id | string | Required. The ID of the user the device belongs to. Must match the user ID used when logging in. |
device_id | string | Required. The ID of the device these keys belong to. Must match the device ID used when logging in. |
algorithms | [string] | Required. The encryption algorithms supported by this device. |
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 | {string: {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. |
Response format:
Parameter | 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. |
Example request:
POST /_matrix/client/r0/keys/upload HTTP/1.1 Content-Type: application/json { "device_keys": { "user_id": "@alice:example.com", "device_id": "JLAFKJWSCS", "algorithms": [ "m.olm.curve25519-aes-sha256", "m.megolm.v1.aes-sha" ], "keys": { "curve25519:JLAFKJWSCS": "3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI", "ed25519:JLAFKJWSCS": "lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI" }, "signatures": { "@alice:example.com": { "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA" } } }, "one_time_keys": { "curve25519:AAAAAQ": "/qyvZvwjiTxGdGU0RCguDCLeR+nmsb3FfNG3/Ve4vU8", "signed_curve25519:AAAAHg": { "key": "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs", "signatures": { "@alice:example.com": { "ed25519:JLAFKJWSCS": "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw" } } }, "signed_curve25519:AAAAHQ": { "key": "j3fR3HemM16M7CWhoI4Sk5ZsdmdfQHsKL1xuSft6MSw", "signatures": { "@alice:example.com": { "ed25519:JLAFKJWSCS": "IQeCEPb9HFk217cU9kw9EOiusC6kMIkoIRnbnfOh5Oc63S1ghgyjShBGpu34blQomoalCyXWyhaaT3MrLZYQAA" } } } } }
Response:
Status code 200:
The provided keys were sucessfully uploaded.
Example
{ "one_time_key_counts": { "curve25519": 10, "signed_curve25519": 20 } }
Returns the current devices and identity keys for the given users.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
timeout | integer | The time (in milliseconds) to wait when downloading keys from remote servers. 10 seconds is the recommended default. |
device_keys | {string: [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. |
token | string | If the client is fetching keys as a result of a device update received in a sync request, this should be the 'since' token of that sync request, or any later sync token. This allows the server to ensure its response contains the keys advertised by the notification in that sync. |
Response format:
Parameter | 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 device_keys result. |
device_keys | {string: {string: DeviceKeys}} | 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. |
Parameter | Type | Description |
---|---|---|
user_id | string | Required. The ID of the user the device belongs to. Must match the user ID used when logging in. |
device_id | string | Required. The ID of the device these keys belong to. Must match the device ID used when logging in. |
algorithms | [string] | Required. The encryption algorithms supported by this device. |
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 | {string: {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. |
Parameter | Type | Description |
---|---|---|
device_display_name | string | The display name which the user set on the device. |
Example request:
POST /_matrix/client/r0/keys/query HTTP/1.1 Content-Type: application/json { "timeout": 10000, "device_keys": { "@alice:example.com": [] }, "token": "string" }
Response:
Status code 200:
The device information
Example
{ "failures": {}, "device_keys": { "@alice:example.com": { "JLAFKJWSCS": { "user_id": "@alice:example.com", "device_id": "JLAFKJWSCS", "algorithms": [ "m.olm.v1.curve25519-aes-sha256", "m.megolm.v1.aes-sha" ], "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" } } } } }
Claims one-time keys for use in pre-key messages.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
timeout | integer | The time (in milliseconds) to wait when downloading keys from remote servers. 10 seconds is the recommended default. |
one_time_keys | {string: {string: string}} | Required. The keys to be claimed. A map from user ID, to a map from device ID to algorithm name. |
Response format:
Parameter | 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 | {string: {string: string or object}} | 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. |
Example request:
POST /_matrix/client/r0/keys/claim HTTP/1.1 Content-Type: application/json { "timeout": 10000, "one_time_keys": { "@alice:example.com": { "JLAFKJWSCS": "signed_curve25519" } } }
Response:
Status code 200:
The claimed keys.
Example
{ "failures": {}, "one_time_keys": { "@alice:example.com": { "JLAFKJWSCS": { "signed_curve25519:AAAAHg": { "key": "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs", "signatures": { "@alice:example.com": { "ed25519:JLAFKJWSCS": "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw" } } } } } } }
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:
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
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. |
Response format:
Parameter | 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. |
Example request:
GET /_matrix/client/r0/keys/changes?from=s72594_4483_1934&to=s75689_5632_2435 HTTP/1.1
Response:
Status code 200:
The list of users who updated their devices.
Example
{ "changed": [ "@alice:example.com", "@bob:example.org" ], "left": [ "@clara:example.com", "@doug:example.org" ] }
This module adds an optional device_lists property to the /sync response, as specified below. The server need only populate this property for an incremental /sync (ie, one where the since parameter was specified). The client is expected to use /keys/query or /keys/changes for the equivalent functionality after an initial sync, as documented in Tracking the device list for a user.
It also adds a one_time_keys_count property. Note the spelling difference with the one_time_key_counts property in the /keys/upload response.
Parameter | Type | Description |
---|---|---|
device_lists | DeviceLists | Optional. Information on e2e device updates. Note: only present on an incremental sync. |
device_one_time_keys_count | {string: integer} | Optional. For each key algorithm, the number of unclaimed one-time keys currently held on the server for this device. |
DeviceLists
Parameter | Type | Description |
---|---|---|
changed | [string] | List of users who have updated their device identity keys, or who now share an encrypted room with the client since the previous sync response. |
left | [string] | List of users with whom we do not share any encrypted rooms anymore since the previous sync response. |
Note
For optimal performance, Alice should be added to changed in Bob's sync only when she adds a new device, or when Alice and Bob now share a room but didn't share any room previously. However, for the sake of simpler logic, a server may add Alice to changed when Alice and Bob share a new room, even if they previously already shared a room.
Example response:
{ "next_batch": "s72595_4483_1934", "rooms": {"leave": {}, "join": {}, "invite": {}}, "device_lists": { "changed": [ "@alice:example.com", ], "left": [ "@bob:example.com", ], }, "device_one_time_keys_count": { "curve25519": 10, "signed_curve25519": 20 } }
This module adds support for controlling the visibility of previous events in a room.
In all cases except world_readable, a user needs to join a room to view events in that room. Once they have joined a room, they will gain access to a subset of events in the room. How this subset is chosen is controlled by the m.room.history_visibility event outlined below. After a user has left a room, they may see any events which they were allowed to see before they left the room, but no events received after they left.
The four options for the m.room.history_visibility event are:
Warning
These options are applied at the point an event is sent. Checks are performed with the state of the m.room.history_visibility event when the event in question is added to the DAG. This means clients cannot retrospectively choose to show or hide history to new users if the setting at that time was more restrictive.
This event controls whether a user can see the events that happened in a room from before they joined.
Content Key | Type | Description |
---|---|---|
history_visibility | enum | Required. Who can see the room history. One of: ["invited", "joined", "shared", "world_readable"] |
Example:
{ "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 } }
Clients that implement this module MUST present to the user the possible options for setting history visibility when creating a room.
Clients may want to display a notice that their events may be read by non-joined people if the value is set to world_readable.
By default if no history_visibility is set, or if the value is not understood, the visibility is assumed to be shared. The rules governing whether a user is allowed to see an event depend on the state of the room at that event.
For m.room.history_visibility events themselves, the user should be allowed to see the event if the history_visibility before or after the event would allow them to see it. (For example, a user should be able to see m.room.history_visibility events which change the history_visibility from world_readable to joined or from joined to world_readable, even if that user was not a member of the room.)
Likewise, for the user's own m.room.member events, the user should be allowed to see the event if their membership before or after the event would allow them to see it. (For example, a user can always see m.room.member events which set their membership to join, or which change their membership from join to any other value, even if history_visibility is joined.)
The default value for history_visibility is shared for backwards-compatibility reasons. Clients need to be aware that by not setting this event they are exposing all of their room history to anyone in the room.
+--------------------+ +-------------------+ Matrix HTTP | | | | Notification Protocol | App Developer | | Device Vendor | | | | | +-------------------+ | +----------------+ | | +---------------+ | | | | | | | | | | | | Matrix homeserver +-----> Push Gateway +------> Push Provider | | | | | | | | | | | | +-^-----------------+ | +----------------+ | | +----+----------+ | | | | | | | Matrix | | | | | | Client/Server API + | | | | | | | +--------------------+ +-------------------+ | +--+-+ | | | <-------------------------------------------+ +---+ | | | Provider Push Protocol +----+ Mobile Device or Client
This module adds support for push notifications. Homeservers send notifications of events to user-configured HTTP endpoints. Users may also configure a number of rules that determine which events generate notifications. These are all stored and managed by the user's homeserver. This allows user-specific push settings to be reused between client applications.
The above diagram shows the flow of push notifications being sent to a handset where push notifications are submitted via the handset vendor, such as Apple's APNS or Google's GCM. This happens as follows:
Definitions for terms used in this section are below:
Clients MUST configure a Pusher before they will receive push notifications. There is a single API endpoint for this, as described below.
Gets all currently active pushers for the authenticated user.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
pushers | [Pusher] | An array containing the current pushers for the user |
Parameter | Type | Description |
---|---|---|
pushkey | string | Required. This is a unique identifier for this pusher. See /set for more detail. Max length, 512 bytes. |
kind | string | Required. The kind of pusher. "http" is a pusher that sends HTTP pokes. |
app_id | string | Required. This is a reverse-DNS style identifier for the application. Max length, 64 chars. |
app_display_name | string | Required. A string that will allow the user to identify what application owns this pusher. |
device_display_name | string | Required. A string that will allow the user to identify what device owns this pusher. |
profile_tag | string | This string determines which set of device specific rules this pusher executes. |
lang | string | Required. The preferred language for receiving notifications (e.g. 'en' or 'en-US') |
data | PusherData | Required. A dictionary of information for the pusher implementation itself. |
Parameter | Type | Description |
---|---|---|
url | string | Required if kind is http. The URL to use to send notifications to. |
format | string | The format to use when sending notifications to the Push Gateway. |
Example request:
GET /_matrix/client/r0/pushers HTTP/1.1
Response:
Status code 200:
The pushers for this user.
Example
{ "pushers": [ { "pushkey": "Xp/MzCt8/9DcSNE9cuiaoT5Ac55job3TdLSSmtmYl4A=", "kind": "http", "app_id": "face.mcapp.appy.prod", "app_display_name": "Appy McAppface", "device_display_name": "Alice's Phone", "profile_tag": "xyz", "lang": "en-US", "data": { "url": "https://example.com/_matrix/push/v1/notify" } } ] }
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.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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. |
kind | string | 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. |
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". |
app_display_name | string | Required. A string that will allow the user to identify what application owns this pusher. |
device_display_name | string | Required. A string that will allow the user to identify what device owns this pusher. |
profile_tag | string | This string determines which set of device specific rules this pusher executes. |
lang | string | Required. The preferred language for receiving notifications (e.g. 'en' or 'en-US'). |
data | PusherData | Required. A dictionary of information for the pusher implementation itself. If kind is http, this should contain url which is the URL to use to send notifications to. |
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. |
Parameter | Type | Description |
---|---|---|
url | string | Required if kind is http. The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify. |
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'. |
Example request:
POST /_matrix/client/r0/pushers/set HTTP/1.1 Content-Type: application/json { "lang": "en", "kind": "http", "app_display_name": "Mat Rix", "device_display_name": "iPhone 9", "profile_tag": "xxyyzz", "app_id": "com.example.app.ios", "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ", "data": { "url": "https://push-gateway.location.here/_matrix/push/v1/notify", "format": "event_id_only" }, "append": false }
Responses:
Status code 200:
The pusher was set.
Example
{}
Status code 400:
One or more of the pusher values were invalid.
Example
{ "error": "Missing parameters: lang, data", "errcode": "M_MISSING_PARAM" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
A client can retrieve a list of events that it has been notified about. This may be useful so that users can see a summary of what important messages they have received.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
from | string | Pagination token given to retrieve the next set of events. |
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. |
Response format:
Parameter | 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. |
Parameter | Type | Description |
---|---|---|
actions | [object or 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. |
Parameter | Type | Description |
---|---|---|
event_id | string | The ID of this event, if applicable. |
content | EventContent | The content of this event. The fields in this object will vary depending on the type of event. |
origin_server_ts | integer | Timestamp in milliseconds on originating homeserver when this event was sent. |
sender | string | The MXID of the user who sent this event. |
state_key | string | Optional. This key will only be present for state events. A unique key which defines the overwriting semantics for this piece of room state. |
type | string | The type of event. |
unsigned | Unsigned | Information about this event which was not sent by the originating homeserver |
Parameter | Type | Description |
---|---|---|
age | integer | Time in milliseconds since the event was sent. |
prev_content | EventContent | Optional. The previous content for this state. This will be present only for state events appearing in the timeline. If this is not a state event, or there is no previous content, this key will be missing. |
transaction_id | string | Optional. The transaction ID set when this message was sent. This key will only be present for message events sent by the device calling this API. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
Example request:
GET /_matrix/client/r0/notifications?from=xxxxx&limit=20&only=highlight HTTP/1.1
Response:
Status code 200:
A batch of events is being returned
Example
{ "next_token": "abcdef", "notifications": [ { "actions": [ "notify" ], "profile_tag": "hcbvkzxhcvb", "read": true, "room_id": "!abcdefg:example.com", "ts": 1475508881945, "event": { "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 } } } ] }
Servers MUST include the number of unread notifications in a client's /sync stream, and MUST update it as it changes. Notifications are determined by the push rules which apply to an event.
When the user updates their read receipt (either by using the API or by sending an event), notifications prior to and including that event MUST be marked as read.
A push rule is a single rule that states under what conditions an event should be passed onto a push gateway and how the notification should be presented. There are different "kinds" of push rules and each rule has an associated priority. Every push rule MUST have a kind and rule_id. The rule_id is a unique string within the kind of rule and its' scope: rule_ids do not need to be unique between rules of the same kind on different devices. Rules may have extra keys depending on the value of kind. The different kinds of rule in descending order of priority are:
This means that the full list of rule kinds, in descending priority order, is as follows:
Rules with the same kind can specify an ordering priority. This determines which rule is selected in the event of multiple matches. For example, a rule matching "tea" and a separate rule matching "time" would both match the sentence "It's time for tea". The ordering of the rules would then resolve the tiebreak to determine which rule is executed. Only actions for highest priority rule will be sent to the Push Gateway.
Each rule can be enabled or disabled. Disabled rules never match. If no rules match an event, the homeserver MUST NOT notify the Push Gateway for that event. Homeservers MUST NOT notify the Push Gateway for events that the user has sent themselves.
All rules have an associated list of actions. An action affects if and how a notification is delivered for a matching event. The following actions are defined:
Actions that have no parameters are represented as a string. Otherwise, they are represented as a dictionary with a key equal to their name and other keys as their parameters, e.g. { "set_tweak": "sound", "value": "default" }
The set_tweak action is used to add an entry to the 'tweaks' dictionary that is sent in the notification request to the Push Gateway. The following tweaks are defined:
Tweaks are passed transparently through the homeserver so client applications and Push Gateways may agree on additional tweaks. For example, a tweak may be added to specify how to flash the notification light on a mobile device.
Homeservers can specify "server-default rules" which operate at a lower priority than "user-defined rules". The rule_id for all server-default rules MUST start with a dot (".") to identify them as "server-default". The following server-default rules are specified:
Matches all events, this can be enabled to turn off all push notifications other than those generated by override rules set by the user. By default this rule is disabled.
Definition
{ "rule_id": ".m.rule.master", "default": true, "enabled": false, "conditions": [], "actions": [ "dont_notify" ] }
Matches messages with a msgtype of notice. This should be an override rule so that it takes priority over content / sender / room rules.
Definition:
{ "rule_id": ".m.rule.suppress_notices", "default": true, "enabled": true, "conditions": [ { "kind": "event_match", "key": "content.msgtype", "pattern": "m.notice", } ], "actions": [ "dont_notify", ] }
Matches any invites to a new room for this user.
Definition:
{ "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" }, { "set_tweak": "highlight", "value": false } ] }
Matches any m.room.member_event.
Definition:
{ "rule_id": ".m.rule.member_event", "default": true, "enabled": true, "conditions": [ { "key": "type", "kind": "event_match", "pattern": "m.room.member" } ], "actions": [ "dont_notify" ] }
Matches any message whose content is unencrypted and contains the user's current display name in the room in which it was sent.
Definition:
{ "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" } ] }
Matches any event whose type is m.room.tombstone. This is intended to notify users of a room when it is upgraded, similar to what an @room notification would accomplish.
Definition:
{ "rule_id": ".m.rule.tombstone", "default": true, "enabled": true, "conditions": [ { "kind": "event_match", "key": "type", "pattern": "m.room.tombstone" } ], "actions": [ "notify", { "set_tweak": "highlight", "value": true } ] }
Matches any message whose content is unencrypted and contains the text @room, signifying the whole room should be notified of the event.
Definition:
{ "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", "value": true } ] }
Matches any message whose content is unencrypted and contains the local part of the user's Matrix ID, separated by word boundaries.
Definition (as a content rule):
{ "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" } ] }
Matches any incoming VOIP call.
Definition:
{ "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" }, { "set_tweak": "highlight", "value": false } ] }
Matches any encrypted event sent in a room with exactly two members. Unlike other push rules, this rule cannot be matched against the content of the event by nature of it being encrypted. This causes the rule to be an "all or nothing" match where it either matches all events that are encrypted (in 1:1 rooms) or none.
Definition:
{ "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" }, { "set_tweak": "highlight", "value": false } ] }
Matches any message sent in a room with exactly two members.
Definition:
{ "rule_id": ".m.rule.room_one_to_one", "default": true, "enabled": true, "conditions": [ { "kind": "room_member_count", "is": "2" } ], "actions": [ "notify", { "set_tweak": "sound", "value": "default" }, { "set_tweak": "highlight", "value": false } ] }
Matches all chat messages.
Definition:
{ "rule_id": ".m.rule.message", "default": true, "enabled": true, "conditions": [ { "kind": "event_match", "key": "type", "pattern": "m.room.message" } ], "actions": [ "notify", { "set_tweak": "highlight", "value": false } ] }
Matches all encrypted events. Unlike other push rules, this rule cannot be matched against the content of the event by nature of it being encrypted. This causes the rule to be an "all or nothing" match where it either matches all events that are encrypted (in group rooms) or none.
Definition:
{ "rule_id": ".m.rule.encrypted", "default": true, "enabled": true, "conditions": [ { "kind": "event_match", "key": "type", "pattern": "m.room.encrypted" } ], "actions": [ "notify", { "set_tweak": "highlight", "value": false } ] }
Override, Underride and Default Rules MAY have a list of 'conditions'. All conditions must hold true for an event in order to apply the action for the event. A rule with no conditions always matches. Room, Sender, User and Content rules do not have conditions in the same way, but instead have predefined conditions. These conditions can be configured using the parameters outlined below. In the cases of room and sender rules, the rule_id of the rule determines its behaviour. The following conditions are defined:
This is a glob pattern match on a field of the event. Parameters:
This matches the current number of members in the room. Parameters:
This takes into account the current power levels in the room, ensuring the sender of the event has high enough power to trigger the notification.
Parameters:
Unrecognised conditions MUST NOT match any events, effectively making the push rule disabled.
Clients can retrieve, add, modify and remove push rules globally or per-device using the APIs below.
Retrieve all push rulesets for this user. Clients can "drill-down" on the rulesets by suffixing a scope to this path e.g. /pushrules/global/. This will return a subset of this data under the specified key e.g. the global key.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
global | Ruleset | Required. The global ruleset. |
Parameter | Type | Description |
---|---|---|
content | [PushRule] | |
override | [PushRule] | |
room | [PushRule] | |
sender | [PushRule] | |
underride | [PushRule] |
Parameter | Type | Description |
---|---|---|
actions | [object or string] | Required. The actions to perform when this rule is matched. |
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. |
rule_id | string | Required. The ID of this rule. |
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 | The glob-style pattern to match against. Only applicable to content rules. |
Parameter | Type | Description |
---|---|---|
kind | string | Required. The kind of condition to apply. See conditions for more information on the allowed kinds and how they work. |
key | string | Required for event_match 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. |
pattern | string | Required for event_match conditions. The glob- style pattern to match against. Patterns with no special glob characters should be treated as having asterisks prepended and appended when testing the condition. |
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 ==. |
Example request:
GET /_matrix/client/r0/pushrules/ HTTP/1.1
Response:
Status code 200:
All the push rulesets for this user.
Example
{ "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": [ "dont_notify" ], "conditions": [], "default": true, "enabled": false, "rule_id": ".m.rule.master" }, { "actions": [ "dont_notify" ], "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" } ], "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" } ] } }
Retrieve a single specified push rule.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. global to specify global rules. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
Response format:
Parameter | Type | Description |
---|---|---|
actions | [object or string] | Required. The actions to perform when this rule is matched. |
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. |
rule_id | string | Required. The ID of this rule. |
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 | The glob-style pattern to match against. Only applicable to content rules. |
Parameter | Type | Description |
---|---|---|
kind | string | Required. The kind of condition to apply. See conditions for more information on the allowed kinds and how they work. |
key | string | Required for event_match 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. |
pattern | string | Required for event_match conditions. The glob- style pattern to match against. Patterns with no special glob characters should be treated as having asterisks prepended and appended when testing the condition. |
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 ==. |
Example request:
GET /_matrix/client/r0/pushrules/global/content/nocake HTTP/1.1
Response:
Status code 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.
Example
{ "actions": [ "dont_notify" ], "pattern": "cake*lie", "rule_id": "nocake", "enabled": true, "default": false }
This endpoint removes the push rule defined in the path.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. global to specify global rules. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
Example request:
DELETE /_matrix/client/r0/pushrules/global/content/nocake HTTP/1.1
Response:
Status code 200:
The push rule was deleted.
Example
{}
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.
When creating push rules, they MUST be enabled by default.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. global to specify global rules. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
query parameters | ||
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. |
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. |
JSON body parameters | ||
actions | [enum] | Required. The action(s) to perform when the conditions for this rule are met. One of: ["notify", "dont_notify", "coalesce", "set_tweak"] |
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. |
Parameter | Type | Description |
---|---|---|
kind | string | Required. The kind of condition to apply. See conditions for more information on the allowed kinds and how they work. |
key | string | Required for event_match 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. |
pattern | string | Required for event_match conditions. The glob- style pattern to match against. Patterns with no special glob characters should be treated as having asterisks prepended and appended when testing the condition. |
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 ==. |
Example request:
PUT /_matrix/client/r0/pushrules/global/content/nocake?before=someRuleId&after=anotherRuleId HTTP/1.1 Content-Type: application/json { "pattern": "cake*lie", "actions": [ "notify" ] }
Responses:
Status code 200:
The push rule was created/updated.
Example
{}
Status code 400:
There was a problem configuring this push rule.
Example
{ "error": "before/after rule not found: someRuleId", "errcode": "M_UNKNOWN" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
This endpoint gets whether the specified push rule is enabled.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. Either global or device/<profile_tag> to specify global rules or device rules for the given profile_tag. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
Response format:
Parameter | Type | Description |
---|---|---|
enabled | boolean | Required. Whether the push rule is enabled or not. |
Example request:
GET /_matrix/client/r0/pushrules/global/cake/nocake/enabled HTTP/1.1
Response:
Status code 200:
Whether the push rule is enabled.
Example
{ "enabled": true }
This endpoint allows clients to enable or disable the specified push rule.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. global to specify global rules. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
JSON body parameters | ||
enabled | boolean | Required. Whether the push rule is enabled or not. |
Example request:
PUT /_matrix/client/r0/pushrules/global/content/nocake/enabled HTTP/1.1 Content-Type: application/json { "enabled": true }
Response:
Status code 200:
The push rule was enabled or disabled.
Example
{}
This endpoint get the actions for the specified push rule.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. Either global or device/<profile_tag> to specify global rules or device rules for the given profile_tag. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
Response format:
Parameter | Type | Description |
---|---|---|
actions | [string] | Required. The action(s) to perform for this rule. |
Example request:
GET /_matrix/client/r0/pushrules/global/content/nocake/actions HTTP/1.1
Response:
Status code 200:
The actions for this push rule.
Example
{ "actions": [ "notify" ] }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
scope | string | Required. global to specify global rules. |
kind | enum | Required. The kind of rule One of: ["override", "underride", "sender", "room", "content"] |
ruleId | string | Required. The identifier for the rule. |
JSON body parameters | ||
actions | [enum] | Required. The action(s) to perform for this rule. One of: ["notify", "dont_notify", "coalesce", "set_tweak"] |
Example request:
PUT /_matrix/client/r0/pushrules/global/room/%23spam%3Aexample.com/actions HTTP/1.1 Content-Type: application/json { "actions": [ "notify" ] }
Response:
Status code 200:
The actions for the push rule were set.
Example
{}
When a user changes their push rules a m.push_rules event is sent to all clients in the account_data section of their next /sync request. The content of the event is the current push rules for the user.
Describes all push rules for this user.
Content Key | Type | Description |
---|---|---|
global | Ruleset | The global ruleset |
Ruleset Key | Type | Description |
---|---|---|
content | [PushRule] | |
override | [PushRule] | |
room | [PushRule] | |
sender | [PushRule] | |
underride | [PushRule] |
PushRule Key | Type | Description |
---|---|---|
actions | [object or string] | Required. The actions to perform when this rule is matched. |
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. |
rule_id | string | Required. The ID of this rule. |
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 | The glob-style pattern to match against. Only applicable to content rules. |
PushCondition Key | Type | Description |
---|---|---|
kind | string | Required. The kind of condition to apply. See conditions for more information on the allowed kinds and how they work. |
key | string | Required for event_match 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. |
pattern | string | Required for event_match conditions. The glob- style pattern to match against. Patterns with no special glob characters should be treated as having asterisks prepended and appended when testing the condition. |
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 ==. |
Example:
{ "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": [ "dont_notify" ], "conditions": [], "default": true, "enabled": false, "rule_id": ".m.rule.master" }, { "actions": [ "dont_notify" ], "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" } ], "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" }
To create a rule that suppresses notifications for the room with ID !dj234r78wl45Gh4D:matrix.org:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/r0/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ '{ "actions" : ["dont_notify"] }'
To suppress notifications for the user @spambot:matrix.org:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/r0/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ '{ "actions" : ["dont_notify"] }'
To always notify for messages that contain the work 'cake' and set a specific sound (with a rule_id of SSByZWFsbHkgbGlrZSBjYWtl):
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/r0/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \ '{ "pattern": "cake", "actions" : ["notify", {"set_sound":"cakealarm.wav"}] }'
To add a rule suppressing notifications for messages starting with 'cake' but ending with 'lie', superseding the previous rule:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/r0/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \ '{ "pattern": "cake*lie", "actions" : ["notify"] }'
To add a custom sound for notifications messages containing the word 'beer' in any rooms with 10 members or fewer (with greater importance than the room, sender and content rules):
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/r0/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_sound":"beeroclock.wav"} ] }'
The exact format for sending APNS notifications is flexible and up to the client app and its' push gateway to agree on. As APNS requires that the sender has a private key owned by the app developer, each app must have its own push gateway. It is recommended that:
Clients specify the Push Gateway URL to use to send event notifications to. This URL should be over HTTPS and never over HTTP.
As push notifications will pass through a Push Provider, message content shouldn't be sent in the push itself where possible. Instead, Push Gateways should send a "sync" command to instruct the client to get new events from the homeserver directly.
This module adds in support for inviting new members to a room where their Matrix user ID is not known, instead addressing them by a third party identifier such as an email address. There are two flows here; one if a Matrix user ID is known for the third party identifier, and one if not. Either way, the client calls /invite with the details of the third party identifier.
The homeserver asks the identity server whether a Matrix user ID is known for that identifier:
When the invitee's homeserver receives the notification of the binding, it should insert an m.room.member event into the room's graph for that user, with content.membership = invite, as well as a content.third_party_invite property which contains proof that the invitee does indeed own that third party identifier. See the m.room.member schema for more information.
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.
Content Key | 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 Key | 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. |
Example:
{ "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 } }
A client asks a server to invite a user by their third party identifier.
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:
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier (not alias) to which to invite the user. |
JSON body parameters | ||
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. |
address | string | Required. The invitee's third party identifier. |
Example request:
POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/invite HTTP/1.1 Content-Type: application/json { "id_server": "matrix.org", "medium": "email", "address": "cheeky@monkey.com" }
Responses:
Status code 200:
The user has been invited to join the room.
Example
{}
Status code 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:
Example
{ "errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room" }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
Upon receipt of an /invite, the server is expected to look up the third party identifier with the provided identity server. If the lookup yields a result for a Matrix User ID then the normal invite process can be initiated. This process ends up looking like this:
+---------+ +-------------+ +-----------------+ | Client | | Homeserver | | IdentityServer | +---------+ +-------------+ +-----------------+ | | | | POST /invite | | |------------------------------------>| | | | | | | GET /lookup | | |--------------------------------------------------->| | | | | | User ID result | | |<---------------------------------------------------| | | | | | Invite process for the discovered User ID | | |------------------------------------------ | | | | | | |<----------------------------------------- | | | | | Complete the /invite request | | |<------------------------------------| | | | |
However, if the lookup does not yield a bound User ID, the homeserver must store the invite on the identity server and emit a valid m.room.third_party_invite event to the room. This process ends up looking like this:
+---------+ +-------------+ +-----------------+ | Client | | Homeserver | | IdentityServer | +---------+ +-------------+ +-----------------+ | | | | POST /invite | | |------------------------------------>| | | | | | | GET /lookup | | |-------------------------------------------------------------->| | | | | | "no users" result | | |<--------------------------------------------------------------| | | | | | POST /store-invite | | |-------------------------------------------------------------->| | | | | | Information needed for the m.room.third_party_invite | | |<--------------------------------------------------------------| | | | | | Emit m.room.third_party_invite to the room | | |------------------------------------------- | | | | | | |<------------------------------------------ | | | | | Complete the /invite request | | |<------------------------------------| | | | |
All homeservers MUST verify the signature in the event's content.third_party_invite.signed object.
The third party user will then need to verify their identity, which results in a call from the identity server to the homeserver that bound the third party identifier to a user. The homeserver then exchanges the m.room.third_party_invite event in the room for a complete m.room.member event for membership: invite for the user that has bound the third party identifier.
If a homeserver is joining a room for the first time because of an m.room.third_party_invite, the server which is already participating in the room (which is chosen as per the standard server-server specification) MUST validate that the public key used for signing is still valid, by checking key_validity_url in the above described way.
No other homeservers may reject the joining of the room on the basis of key_validity_url, this is so that all homeservers have a consistent view of the room. They may, however, indicate to their clients that a member's membership is questionable.
For example, given H1, H2, and H3 as homeservers, UserA as a user of H1, and an identity server IS, the full sequence for a third party invite would look like the following. This diagram assumes H1 and H2 are residents of the room while H3 is attempting to join.
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+ | UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS | +-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+ | | | | | | | POST /invite for ThirdPartyUser | | | | |----------------------------------->| | | | | | | | | | | | | GET /lookup | | | | | |---------------------------------------------------------------------------------------------->| | | | | | | | | | | Lookup results (empty object) | | | |<----------------------------------------------------------------------------------------------| | | | | | | | | | POST /store-invite | | | | | |---------------------------------------------------------------------------------------------->| | | | | | | | | | | Token, keys, etc for third party invite | | | |<----------------------------------------------------------------------------------------------| | | | | | | | | | (Federation) Emit m.room.third_party_invite | | | | | |----------------------------------------------->| | | | | | | | | | Complete /invite request | | | | |<-----------------------------------| | | | | | | | | | | | Verify identity | | | | | |-------------------------------------------------------------------------------------------------------------------->| | | | | | | | | | | | POST /3pid/onbind | | | | | |<---------------------------| | | | | | | | | | PUT /exchange_third_party_invite/:roomId | | | | |<-----------------------------------------------------------------| | | | | | | | | | | Verify the request | | | | | |------------------- | | | | | | | | | | | | |<------------------ | | | | | | | | | | | | (Federation) Emit m.room.member for invite | | | | | |----------------------------------------------->| | | | | | | | | | | | | | | | | | (Federation) Emit the m.room.member event sent to H2 | | | | |----------------------------------------------------------------->| | | | | | | | | | | Complete /exchange_third_party_invite/:roomId request | | | | |----------------------------------------------------------------->| | | | | | | | | | | | | Participate in the room | | | | | |------------------------ | | | | | | | | | | | | |<----------------------- | | | | | | |
Note that when H1 sends the m.room.member event to H2 and H3 it does not have to block on either server's receipt of the event. Likewise, H1 may complete the /exchange_third_party_invite/:roomId request at the same time as sending the m.room.member event to H2 and H3. Additionally, H3 may complete the /3pid/onbind request it got from IS at any time - the completion is not shown in the diagram.
H1 MUST verify the request from H3 to ensure the signed property is correct as well as the key_validity_url as still being valid. This is done by making a request to the identity server /isvalid endpoint, using the provided URL rather than constructing a new one. The query string and response for the provided URL must match the Identity Service Specification.
The reason that no other homeserver may reject the event based on checking key_validity_url is that we must ensure event acceptance is deterministic. If some other participating server doesn't have a network path to the keyserver, or if the keyserver were to go offline, or revoke its keys, that other server would reject the event and cause the participating servers' graphs to diverge. This relies on participating servers trusting each other, but that trust is already implied by the server-server protocol. Also, the public key signature verification must still be performed, so the attack surface here is minimized.
There are a number of privacy and trust implications to this module.
It is important for user privacy that leaking the mapping between a matrix user ID and a third party identifier is hard. In particular, being able to look up all third party identifiers from a matrix user ID (and accordingly, being able to link each third party identifier) should be avoided wherever possible. To this end, the third party identifier is not put in any event, rather an opaque display name provided by the identity server is put into the events. Clients should not remember or display third party identifiers from invites, other than for the use of the inviter themself.
Homeservers are not required to trust any particular identity server(s). It is generally a client's responsibility to decide which identity servers it trusts, not a homeserver's. Accordingly, this API takes identity servers as input from end users, and doesn't have any specific trusted set. It is possible some homeservers may want to supply defaults, or reject some identity servers for its users, but no homeserver is allowed to dictate which identity servers other homeservers' users trust.
There is some risk of denial of service attacks by flooding homeservers or identity servers with many requests, or much state to store. Defending against these is left to the implementer's discretion.
The search API allows clients to perform full text search across events in all rooms that the user has been in, including those that they have left. Only events that the user is allowed to see will be searched, e.g. it won't include events in rooms that happened after you left.
There is a single HTTP API for performing server-side search, documented below.
Performs a full text search across different categories.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
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. |
JSON body parameters | ||
search_categories | Categories | Required. Describes which categories to search in and their criteria. |
Parameter | Type | Description |
---|---|---|
room_events | Room Events Criteria | Mapping of category name to search criteria. |
Parameter | Type | Description |
---|---|---|
search_term | string | Required. The string to search events for |
keys | [enum] | The keys to search. Defaults to all. One of: ["content.body", "content.name", "content.topic"] |
filter | Filter | This takes a filter. |
order_by | enum | The order in which to search for results. By default, this is "rank". One of: ["recent", "rank"] |
event_context | Include Event Context | Configures whether any context for the events returned are included in the response. |
include_state | boolean | Requests the server return the current state for each room returned. |
groupings | Groupings | Requests that the server partitions the result set based on the provided list of keys. |
Parameter | Type | Description |
---|---|---|
limit | integer | The maximum number of events to return. |
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. |
lazy_load_members | boolean | If true, enables lazy-loading of membership events. See Lazy-loading room members for more information. Defaults to false. |
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. |
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. |
rooms | [string] | A list of room IDs to include. If this list is absent then all rooms are included. |
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. |
Parameter | Type | Description |
---|---|---|
before_limit | integer | How many events before the result are returned. By default, this is 5. |
after_limit | integer | How many events after 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. |
Parameter | Type | Description |
---|---|---|
group_by | [Group] | List of groups to request. |
Parameter | Type | Description |
---|---|---|
key | enum | Key that defines the group. One of: ["room_id", "sender"] |
Response format:
Parameter | Type | Description |
---|---|---|
search_categories | Result Categories | Required. Describes which categories to search in and their criteria. |
Parameter | Type | Description |
---|---|---|
room_events | Result Room Events | Mapping of category name to search criteria. |
Parameter | Type | Description |
---|---|---|
count | integer | An approximate count of the total number of results found. |
highlights | [string] | List of words which should be highlighted, useful for stemming which may change the query terms. |
results | [Result] | List of results in the requested order. |
state | {string: [State Event]} | 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 string key is the room ID for which the State Event array belongs to. |
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). |
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. |
Parameter | Type | Description |
---|---|---|
rank | number | A number that describes how closely this result matches the search. Higher is closer. |
result | Event | The event that matched. |
context | Event Context | Context for result, if requested. |
Parameter | Type | Description |
---|---|---|
start | string | Pagination token for the start of the chunk |
end | string | Pagination token for the end of the chunk |
profile_info | {string: User Profile} | The historic profile information of the users that sent the events returned. The string key is the user ID for which the profile belongs to. |
events_before | [Event] | Events just before the result. |
events_after | [Event] | Events just after the result. |
Parameter | Type | Description |
---|---|---|
displayname | string | |
avatar_url | string |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Parameter | 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. |
Example request:
POST /_matrix/client/r0/search?next_batch=YWxsCgpOb25lLDM1ODcwOA HTTP/1.1 Content-Type: application/json { "search_categories": { "room_events": { "keys": [ "content.body" ], "search_term": "martians and men", "order_by": "recent", "groupings": { "group_by": [ { "key": "room_id" } ] } } } }
Responses:
Status code 200:
Results of the search.
Example
{ "search_categories": { "room_events": { "groups": { "room_id": { "!qPewotXpIctQySfjSy:localhost": { "order": 1, "next_batch": "BdgFsdfHSf-dsFD", "results": [ "$144429830826TWwbB:localhost" ] } } }, "highlights": [ "martians", "men" ], "next_batch": "5FdgFsd234dfgsdfFD", "count": 1224, "results": [ { "rank": 0.00424866, "result": { "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": "$144429830826TWwbB:localhost", "room_id": "!qPewotXpIctQySfjSy:localhost", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } } ] } } }
Status code 400:
Part of the request was invalid.
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
The search API allows clients to search in different categories of items. Currently the only specified category is room_events.
This category covers all events that the user is allowed to see, including events in rooms that they have left. The search is performed on certain keys of certain event types.
The supported keys to search over are:
The search will not include rooms that are end to end encrypted.
The results include a rank key that can be used to sort the results by relevancy. The higher the rank the more relevant the result is.
The value of count gives an approximation of the total number of results. Homeservers may give an estimate rather than an exact value for this field.
The client can specify the ordering that the server returns results in. The two allowed orderings are:
The default ordering is rank.
The client can request that the results are returned along with grouping information, e.g. grouped by room_id. In this case the response will contain a group entry for each distinct value of room_id. Each group entry contains at least a list of the event_ids that are in that group, as well as potentially other metadata about the group.
The current required supported groupings are:
The server may return a next_batch key at various places in the response. These are used to paginate the results. To fetch more results, the client should send the same request to the server with a next_batch query parameter set to that of the token.
The scope of the pagination is defined depending on where the next_batch token was returned. For example, using a token inside a group will return more results from within that group.
The currently supported locations for the next_batch token are:
A server need not support pagination, even if there are more matching results. In that case, they must not return a next_batch token in the response.
The server must only return results that the user has permission to see.
There are times when it is desirable for clients to be able to interact with rooms without having to fully register for an account on a homeserver or join the room. This module specifies how these clients should interact with servers in order to participate in rooms as guests.
Guest users retrieve access tokens from a homeserver using the ordinary register endpoint, specifying the kind parameter as guest. They may then interact with the client-server API as any other user would, but will only have access to a subset of the API as described the Client behaviour subsection below. Homeservers may choose not to allow this access at all to their local users, but have no information about whether users on other homeservers are guests or not.
Guest users can also upgrade their account by going through the ordinary register flow, but specifying the additional POST parameter guest_access_token containing the guest's access token. They are also required to specify the username parameter to the value of the local part of their username, which is otherwise optional.
This module does not fully factor in federation; it relies on individual homeservers properly adhering to the rules set out in this module, rather than allowing all homeservers to enforce the rules on each other.
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".
Content Key | Type | Description |
---|---|---|
guest_access | enum | Required. Whether guests can join the room. One of: ["can_join", "forbidden"] |
Example:
{ "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 } }
The following API endpoints are allowed to be accessed by guest accounts for retrieving events:
The following API endpoints are allowed to be accessed by guest accounts for sending events:
The following API endpoints are allowed to be accessed by guest accounts for their own account maintenance:
The following API endpoints are allowed to be accessed by guest accounts for end-to-end encryption:
Servers MUST only allow guest users to join rooms if the m.room.guest_access state event is present on the room, and has the guest_access value can_join. If the m.room.guest_access event is changed to stop this from being the case, the server MUST set those users' m.room.member state to leave.
Each homeserver manages its own guest accounts itself, and whether an account is a guest account or not is not information passed from server to server. Accordingly, any server participating in a room is trusted to properly enforce the permissions outlined in this section.
Homeservers may want to enable protections such as captchas for guest registration to prevent spam, denial of service, and similar attacks.
It is sometimes desirable to offer a preview of a room, where a user can "lurk" and read messages posted to the room, without joining the room. This can be particularly effective when combined with Guest Access.
Previews are implemented via the world_readable Room History Visibility. setting, along with a special version of the GET /events endpoint.
A client wishing to view a room without joining it should call GET /rooms/:room_id/initialSync, followed by GET /events. Clients will need to do this in parallel for each room they wish to view.
Clients can of course also call other endpoints such as GET /rooms/:room_id/messages and GET /search to access events outside the /events stream.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
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. |
room_id | string | The room ID for which events should be returned. |
Response format:
Parameter | Type | Description |
---|---|---|
start | string | A token which correlates to the first value in chunk. This is usually the same token supplied to from=. |
end | string | A token which correlates to the last value in chunk. This token should be used in the next request to /events. |
chunk | [Event] | An array of events. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
GET /_matrix/client/r0/events?from=s3456_9_0&timeout=35000&room_id=%21somewhere%3Aover.the.rainbow HTTP/1.1
Responses:
Status code 200:
The events received, which may be none.
Example
{ "start": "s3456_9_0", "end": "s3457_9_0", "chunk": [ { "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": "!somewhere:over.the.rainbow", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ] }
Status code 400:
Bad pagination from parameter.
For clients which have not joined a room, servers are required to only return events where the room state at the event had the m.room.history_visibility state event present with history_visibility value world_readable.
Clients may wish to display to their users that rooms which are world_readable may be showing messages to non-joined users. There is no way using this module to find out whether any non-joined guest users do see events in the room, or to list or count any lurking users.
Users can add tags to rooms. Tags are namespaced strings used to label rooms. A room may have multiple tags. Tags are only visible to the user that set them but are shared across all their devices.
The tags on a room are received as single m.tag event in the account_data section of a room. The content of the m.tag event is a tags key whose value is an object mapping the name of each tag to another object.
The JSON object associated with each tag gives information about the tag, e.g how to order the rooms with a given tag.
Ordering information is given under the order key as a number between 0 and 1. The numbers are compared such that 0 is displayed first. Therefore a room with an order of 0.2 would be displayed before a room with an order of 0.7. If a room has a tag without an order key then it should appear after the rooms with that tag that have an order key.
The name of a tag MUST NOT exceed 255 bytes.
The tag namespace is defined as follows:
Two special names are listed in the specification: The following tags are defined in the m.* namespace:
Informs the client of tags on a room.
Content Key | Type | Description |
---|---|---|
tags | {string: Tag} | The tags on the room and their contents. |
Tag Key | Type | Description |
---|---|---|
order | number | A number in a range [0,1] describing a relative position of the room under the given tag. |
Example:
{ "content": { "tags": { "u.work": { "order": 0.9 } } }, "type": "m.tag" }
List the tags set by a user on a room.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
roomId | string | Required. The ID of the room to get tags for. |
Response format:
Parameter | Type | Description |
---|---|---|
tags | {string: Tag} |
Parameter | Type | Description |
---|---|---|
order | number | A number in a range [0,1] describing a relative position of the room under the given tag. |
Example request:
GET /_matrix/client/r0/user/%40alice%3Aexample.com/rooms/%21726s6s6q%3Aexample.com/tags HTTP/1.1
Response:
Status code 200:
The list of tags for the user for the room.
Example
{ "tags": { "m.favourite": { "order": 0.1 }, "u.Work": { "order": 0.7 }, "u.Customers": {} } }
Add a tag to the room.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
roomId | string | Required. The ID of the room to add a tag to. |
tag | string | Required. The tag to add. |
JSON body parameters | ||
order | number | A number in a range [0,1] describing a relative position of the room under the given tag. |
Example request:
PUT /_matrix/client/r0/user/%40alice%3Aexample.com/rooms/%21726s6s6q%3Aexample.com/tags/u.work HTTP/1.1 Content-Type: application/json { "order": 0.25 }
Response:
Status code 200:
The tag was successfully added.
Example
{}
Remove a tag from the room.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
roomId | string | Required. The ID of the room to remove a tag from. |
tag | string | Required. The tag to remove. |
Example request:
DELETE /_matrix/client/r0/user/%40alice%3Aexample.com/rooms/%21726s6s6q%3Aexample.com/tags/u.work HTTP/1.1
Response:
Status code 200:
The tag was successfully removed.
Example
{}
Clients can store custom config data for their account on their homeserver. This account data will be synced between different devices and can persist across installations on a particular device. Users may only view the account data for their own account
The account_data may be either global or scoped to a particular rooms.
The client receives the account data as events in the account_data sections of a /sync.
These events can also be received in a /events response or in the account_data section of a room in /sync. m.tag events appearing in /events will have a room_id with the room the tags are for.
Set some account_data for the client. This config is only visible to the user that set the account_data. The config will be synced to clients in the top-level account_data.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
type | string | Required. The event type of the account_data to set. Custom types should be namespaced to avoid clashes. |
Example request:
PUT /_matrix/client/r0/user/%40alice%3Aexample.com/account_data/org.example.custom.config HTTP/1.1 Content-Type: application/json { "custom_account_data_key": "custom_config_value" }
Response:
Status code 200:
The account_data was successfully added.
Get some account_data for the client. This config is only visible to the user that set the account_data.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
type | string | Required. The event type of the account_data to get. Custom types should be namespaced to avoid clashes. |
Example request:
GET /_matrix/client/r0/user/%40alice%3Aexample.com/account_data/org.example.custom.config HTTP/1.1
Response:
Status code 200:
The account data content for the given type.
Example
{ "custom_account_data_key": "custom_config_value" }
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 synced to clients in the per-room account_data.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
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. |
Example request:
PUT /_matrix/client/r0/user/%40alice%3Aexample.com/rooms/%21726s6s6q%3Aexample.com/account_data/org.example.custom.room.config HTTP/1.1 Content-Type: application/json { "custom_account_data_key": "custom_account_data_value" }
Response:
Status code 200:
The account_data was successfully added.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
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. |
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. |
Example request:
GET /_matrix/client/r0/user/%40alice%3Aexample.com/rooms/%21726s6s6q%3Aexample.com/account_data/org.example.custom.room.config HTTP/1.1
Response:
Status code 200:
The account data content for the given type.
Example
{ "custom_account_data_key": "custom_config_value" }
Servers MUST reject clients from setting account data for event types that the server manages. Currently, this only includes m.fully_read.
This module adds capabilities for server administrators to inspect server state and data.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user to look up. |
Response format:
Parameter | Type | Description |
---|---|---|
user_id | string | The Matrix user ID of the user. |
devices | {string: DeviceInfo} | Each key is an identitfier for one of the user's devices. |
Parameter | Type | Description |
---|---|---|
sessions | [SessionInfo] | A user's sessions (i.e. what they did with an access token from one login). |
Parameter | Type | Description |
---|---|---|
connections | [ConnectionInfo] | Information particular connections in the session. |
Parameter | 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. |
Example request:
GET /_matrix/client/r0/admin/whois/%40peter%3Arabbit.rocks HTTP/1.1
Response:
Status code 200:
The lookup was successful.
Example
{ "user_id": "@peter:rabbit.rocks", "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" } ] } ] } } }
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.
There is a single HTTP API for retrieving event context, documented below.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get events from. |
eventId | string | Required. The event to get context around. |
query parameters | ||
limit | integer | The maximum number of events to return. Default: 10. |
Response format:
Parameter | Type | Description |
---|---|---|
start | string | A token that can be used to paginate backwards with. |
end | string | A token that can be used to paginate forwards with. |
events_before | [Room Event] | A list of room events that happened just before the requested event, in reverse-chronological order. |
event | Room Event | Details of the requested event. |
events_after | [Room Event] | A list of room events that happened just after the requested event, in chronological order. |
state | [State Event] | The state of the room at the last event returned. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
Parameter | 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' |
event_id | string | Required. The globally unique event identifier. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
origin_server_ts | integer | Required. Timestamp in milliseconds on originating homeserver when this event was sent. |
unsigned | UnsignedData | Contains optional extra information about the event. |
room_id | string | Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | Required. A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. 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. |
Parameter | 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. |
redacted_because | Event | Optional. The event that redacted this event, if any. |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/context/%24f3h4d129462ha%3Aexample.com?limit=3 HTTP/1.1
Response:
Status code 200:
The events and state surrounding the requested event.
Example
{ "end": "t29-57_2_0_2", "events_after": [ { "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": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ], "event": { "content": { "body": "filename.jpg", "info": { "h": 398, "w": 394, "mimetype": "image/jpeg", "size": 31037 }, "url": "mxc://example.org/JWEIFJgwEIhweiWJE", "msgtype": "m.image" }, "type": "m.room.message", "event_id": "$f3h4d129462ha:example.com", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } }, "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" }, "type": "m.room.message", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 } } ], "start": "t27-54_2_0_2", "state": [ { "content": { "creator": "@example:example.org", "room_version": "1", "m.federate": true, "predecessor": { "event_id": "$something:example.org", "room_id": "!oldroom:example.org" } }, "type": "m.room.create", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "" }, { "content": { "membership": "join", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "type": "m.room.member", "event_id": "$143273582443PhrSn:example.org", "room_id": "!636q39766251:example.com", "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { "age": 1234 }, "state_key": "@alice:example.org" } ] }
The server must only return results that the user has permission to see.
Single Sign-On (SSO) is a generic term which refers to protocols which allow users to log into applications via a single web-based authentication portal. Examples include "Central Authentication Service" (CAS) and SAML.
An overview of the process, as used in Matrix, is as follows:
Note
In the older r0.4.0 version of this specification it was possible to authenticate via CAS when the server provides a m.login.cas login flow. This specification deprecates the use of m.login.cas to instead prefer m.login.sso, which is the same process with the only change being which redirect endpoint to use: for m.login.cas, use /cas/redirect and for m.login.sso use /sso/redirect (described below). The endpoints are otherwise the same.
The client starts the process by instructing the browser to navigate to /login/sso/redirect with an appropriate redirectUrl. Once authentication is successful, the browser will be redirected to that redirectUrl.
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.
Rate-limited: | No. |
---|---|
Requires auth: | No. |
Request format:
Parameter | Type | Description |
---|---|---|
query parameters | ||
redirectUrl | string | Required. URI to which the user will be redirected after the homeserver has authenticated the user with SSO. |
Example request:
GET /_matrix/client/r0/login/sso/redirect HTTP/1.1
Response:
Status code 302:
A redirect to the SSO interface.
The URI for the SSO system to be used should be configured on the server by the server administrator. The server is expected to set up any endpoints required to interact with that SSO system. For example, for CAS authentication the homeserver should provide a means for the administrator to configure where the CAS server is and the REST endpoints which consume the ticket. A good reference for how CAS could be implemented is available in the older r0.4.0 version of this specification.
When responding to the /login/sso/redirect endpoint, the server must generate a URI for the SSO login page with any appropriate parameters.
Once the homeserver has verified the user's identity with the SSO system, it MUST map the user ID to a valid Matrix user identifier. The guidance in Mapping from other character sets may be useful.
If the generated user identifier represents a new user, it should be registered as a new user.
Finally, the server should generate a short-term login token. The generated token should be a macaroon, suitable for use with the m.login.token type of the /login API, and token-based interactive login. The lifetime of this token SHOULD be limited to around five seconds. This token is given to the client via the loginToken query parameter previously mentioned.
All communication over Matrix happens within a room. It is sometimes desirable to offer users the concept of speaking directly to one particular person. This module defines a way of marking certain rooms as 'direct chats' with a given person. This does not restrict the chat to being between exactly two people since this would preclude the presence of automated 'bot' users or even a 'personal assistant' who is able to answer direct messages on behalf of the user in their absence.
A room may not necessarily be considered 'direct' by all members of the room, but a signalling mechanism exists to propagate the information of whether a chat is 'direct' to an invitee.
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.
Example:
{ "content": { "@bob:example.com": [ "!abcdefgh:example.com", "!hgfedcba:example.com" ] }, "type": "m.direct" }
To start a direct chat with another user, the inviting user's client should set the is_direct flag to /createRoom. The client should do this whenever the flow the user has followed is one where their intention is to speak directly with another person, as opposed to bringing that person in to a shared room. For example, clicking on 'Start Chat' beside a person's profile picture would imply the is_direct flag should be set.
The invitee's client may use the is_direct flag in the m.room.member event to automatically mark the room as a direct chat but this is not required: it may for example, prompt the user, or ignore the flag altogether.
Both the inviting client and the invitee's client should record the fact that the room is a direct chat by storing an m.direct event in the account data using /user/<user_id>/account_data/<type>.
When the is_direct flag is given to /createRoom, the home server must set the is_direct flag in the invite member event for any users invited in the /createRoom call.
With all the communication through Matrix it may be desirable to ignore a particular user for whatever reason. This module defines how clients and servers can implement the ignoring of users.
A map of users which are considered ignored is kept in account_data in an event type of m.ignored_user_list.
Content Key | Type | Description |
---|---|---|
ignored_users | Ignored users | Required. The map of users to ignore |
Ignored users Key | Type | Description |
---|---|---|
$USER_ID | Ignored User | An empty object for future enhancement |
Example:
{ "content": { "ignored_users": { "@someone:example.org": {} } }, "type": "m.ignored_user_list" }
To ignore a user, effectively blocking them, the client should add the target user to the m.ignored_user_list event in their account data using /user/<user_id>/account_data/<type>. Once ignored, the client will no longer receive events sent by that user, with the exception of state events. The client should either hide previous content sent by the newly ignored user or perform a new /sync with no previous token.
Invites to new rooms by ignored users will not be sent to the client. The server may optionally reject the invite on behalf of the client.
State events will still be sent to the client, even if the user is ignored. This is to ensure parts, such as the room name, do not appear different to the user just because they ignored the sender.
To remove a user from the ignored users list, remove them from the account data event. The server will resume sending events from the previously ignored user, however it should not send events that were missed while the user was ignored. To receive the events that were sent while the user was ignored the client should perform a fresh sync. The client may also un-hide any events it previously hid due to the user becoming ignored.
Following an update of the m.ignored_user_list, the sync API for all clients should immediately start ignoring (or un-ignoring) the user. Clients are responsible for determining if they should hide previously sent events or to start a new sync stream.
Servers must still send state events sent by ignored users to clients.
Servers must not send room invites from ignored users to clients. Servers may optionally decide to reject the invite, however.
This module allows users to send sticker messages in to rooms or direct messaging sessions.
Sticker messages are specialised image messages that are displayed without controls (e.g. no "download" link, or light-box view on click, as would be displayed for for m.image events).
Sticker messages are intended to provide simple "reaction" events in the message timeline. The matrix client should provide some mechanism to display the sticker "body" e.g. as a tooltip on hover, or in a modal when the sticker image is clicked.
Sticker events are received as a single m.sticker event in the timeline section of a room, in a /sync.
Message Event
This message represents a single sticker image.
Content Key | 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 Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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_url | string | The URL (typically MXC URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted. |
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. |
ThumbnailInfo Key | Type | Description |
---|---|---|
h | integer | The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file. |
w | integer | The intended display width 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. |
Example:
{ "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 } }
Clients supporting this message type should display the image content from the event URL directly in the timeline.
A thumbnail image should be provided in the info object. This is largely intended as a fallback for clients that do not fully support the m.sticker event type. In most cases it is fine to set the thumbnail URL to the same URL as the main event content.
It is recommended that sticker image content should be 512x512 pixels in size or smaller. The dimensions of the image file should be twice the intended display size specified in the info object in order to assist rendering sharp images on higher DPI screens.
Users may encounter content which they find inappropriate and should be able to report it to the server administrators or room moderators for review. This module defines a way for users to report content.
Content is reported based upon a negative score, where -100 is "most offensive" and 0 is "inoffensive".
Reports an event as inappropriate to the server, which may then notify the appropriate people.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room in which the event being reported is located. |
eventId | string | Required. The event to report. |
JSON body parameters | ||
score | integer | Required. The score to rate this content as where -100 is most offensive and 0 is inoffensive. |
reason | string | Required. The reason the content is being reported. May be blank. |
Example request:
POST /_matrix/client/r0/rooms/%21637q39766251%3Aexample.com/report/%24something%3Aexample.org HTTP/1.1 Content-Type: application/json { "score": -100, "reason": "this makes me sad" }
Response:
Status code 200:
The event has been reported successfully.
Example
{}
Servers are free to handle the reported content however they desire. This may be a dedicated room to alert server administrators to the reported content or some other mechanism for notifying the appropriate people.
Application services can provide access to third party networks via bridging. This allows Matrix users to communicate with users on other communication platforms, with messages ferried back and forth by the application service. A single application service may bridge multiple third party networks, and many individual locations within those networks. A single third party network location may be bridged to multiple Matrix rooms.
A client may wish to provide a rich interface for joining third party locations and connecting with third party users. Information necessary for such an interface is provided by third party lookups.
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 auth: | Yes. |
Request format:
No parameters
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 | {string: Field Type} | 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/client/r0/thirdparty/protocols HTTP/1.1
Response:
Status code 200:
The protocols supported by the homeserver.
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": {} } ] } }
Fetches the metadata from the homeserver about a particular third party protocol.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
protocol | string | Required. The name of the protocol. |
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 | {string: Field Type} | 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/client/r0/thirdparty/protocol/irc HTTP/1.1
Responses:
Status code 200:
The protocol was found and metadata returned.
Example
{ "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": [ { "desc": "Freenode", "icon": "mxc://example.org/JkLmNoPq", "fields": { "network": "freenode" }, "network_id": "freenode" } ] }
Status code 404:
The protocol is unknown.
Example
{ "errcode": "M_NOT_FOUND" }
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
protocol | string | Required. The protocol used to communicate to the third party network. |
query parameters | ||
searchFields | string | One or more custom fields 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/client/r0/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 404:
No portal rooms were found.
Example
{ "errcode": "M_NOT_FOUND" }
Retrieve a Matrix User ID linked to a user on the third party service, given a set of user parameters.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
protocol | string | Required. The name of the protocol. |
query parameters | ||
fields... | string | One or more custom fields that are passed to the AS 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/client/r0/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 404:
The Matrix User ID was not found
Example
{ "errcode": "M_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 | Required. 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/client/r0/thirdparty/location?alias=%23matrix%3Amatrix.org 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 404:
The Matrix room alias was not found
Example
{ "errcode": "M_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 | Required. 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/client/r0/thirdparty/user?userid=%40bob%3Amatrix.org 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 404:
The Matrix User ID was not found
Example
{ "errcode": "M_NOT_FOUND" }
This module allows users to verify their identity with a third party service. The third party service does need to be matrix-aware in that it will need to know to resolve matrix homeservers to exchange the user's token for identity information.
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 auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user to request and OpenID token for. Should be the user who is authenticated for the request. |
Response format:
Parameter | 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. |
token_type | string | Required. The string Bearer. |
matrix_server_name | string | Required. The homeserver domain the consumer should use when attempting 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. |
Example request:
POST /_matrix/client/r0/user/%40alice%3Aexample.com/openid/request_token HTTP/1.1 Content-Type: application/json {}
Responses:
Status code 200:
OpenID token information. This response is nearly compatible with the response documented in the OpenID 1.0 Specification with the only difference being the lack of an id_token. Instead, the Matrix homeserver's name is provided.
Example
{ "access_token": "SomeT0kenHere", "token_type": "Bearer", "matrix_server_name": "example.com", "expires_in": 3600 }
Status code 429:
This request was rate-limited.
Example
{ "errcode": "M_LIMIT_EXCEEDED", "error": "Too many requests", "retry_after_ms": 2000 }
In some scenarios room operators may wish to prevent a malicious or untrusted server from participating in their room. Sending an m.room.server_acl state event into a room is an effective way to prevent the server from participating in the room at the federation level.
Server ACLs can also be used to make rooms only federate with a limited set of servers, or retroactively make the room no longer federate with any other server, similar to setting the m.federate value on the m.room.create event.
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 globs supporting ? and * as wildcards. 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:
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.
Content Key | Type | Description |
---|---|---|
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. |
allow | [string] | The server names to allow in the room, excluding any port information. Wildcards may be used to cover a wider range of hosts, where * matches zero or more characters and ? matches exactly one character. This defaults to an empty list when not provided, effectively disallowing every server. |
deny | [string] | The server names to disallow in the room, excluding any port information. Wildcards may be used to cover a wider range of hosts, where * matches zero or more characters and ? matches exactly one character. This defaults to an empty list when not provided. |
Example:
{ "age": 242352, "content": { "allow": [ "*" ], "allow_ip_literals": false, "deny": [ "*.evil.com", "evil.com" ] }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.server_acl" }
Note
Port numbers are not supported because it is unclear to parsers whether a port number should be matched or an IP address literal. Additionally, it is unlikely that one would trust a server running on a particular domain's port but not a different port, especially considering the server host can easily change ports.
Note
CIDR notation is not supported for IP addresses because Matrix does not encourage the use of IPs for identifying servers. Instead, a blanket allow_ip_literals is provided to cover banning them.
Clients are not expected to perform any additional duties beyond sending the event. Clients should describe changes to the server ACLs to the user in the user interface, such as in the timeline.
Clients may wish to kick affected users from the room prior to denying a server access to the room to help prevent those servers from participating and to provide feedback to the users that they have been excluded from the room.
Servers MUST prevent blacklisted servers from sending events or participating in the room when an m.room.server_acl event is present in the room state. Which APIs are specifically affected are described in the Server-Server API specification.
Servers should still send events to denied servers if they are still residents of the room.
Server ACLs are only effective if every server in the room honours them. Servers that do not honour the ACLs may still permit events sent by denied servers into the room, leaking them to other servers in the room. To effectively enforce an ACL in a room, the servers that do not honour the ACLs should be denied in the room as well.
This module allows users to mention other users, rooms, and groups within a room message. This is achieved by including a matrix.to URI in the HTML body of an m.room.message event. This module does not have any server-specific behaviour to it.
Mentions apply only to m.room.message events where the msgtype is m.text, m.emote, or m.notice. The format for the event must be org.matrix.custom.html and therefore requires a formatted_body.
To make a mention, reference the entity being mentioned in the formatted_body using an anchor, like so:
{ "body": "Hello Alice!", "msgtype": "m.text", "format": "org.matrix.custom.html", "formatted_body": "Hello <a href='https://matrix.to/#/@alice:example.org'>Alice</a>!" }
In addition to using the appropriate matrix.to URI for the mention, clients should use the following guidelines when making mentions in events to be sent:
The text component of the anchor should be used in the event's body where the mention would normally be represented, as shown in the example above.
Clients should display mentions differently from other elements. For example, this may be done by changing the background color of the mention to indicate that it is different from a normal link.
If the current user is mentioned in a message (either by a mention as defined in this module or by a push rule), the client should show that mention differently from other mentions, such as by using a red background color to signify to the user that they were mentioned.
When clicked, the mention should navigate the user to the appropriate room, group, or user information.
From time to time, a room may need to be upgraded to a different room version for a variety for reasons. This module defines a way for rooms to upgrade to a different room version when needed.
A state event signifying that a room has been upgraded to a different room version, and that clients should go there.
Content Key | Type | Description |
---|---|---|
body | string | Required. A server-defined message. |
replacement_room | string | Required. The new room the client should be visiting. |
Example:
{ "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 } }
Clients which understand m.room.tombstone events and the predecessor field on m.room.create events should communicate to the user that the room was upgraded. One way of accomplishing this would be hiding the old room from the user's room list and showing banners linking between the old and new room - ensuring that permalinks work when referencing the old room. Another approach may be to virtually merge the rooms such that the old room's timeline seamlessly continues into the new timeline without the user having to jump between the rooms.
Upgrades the given room to a particular room version.
Rate-limited: | No. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The ID of the room to upgrade. |
JSON body parameters | ||
new_version | string | Required. The new version for the room. |
Response format:
Parameter | Type | Description |
---|---|---|
replacement_room | string | Required. The ID of the new room. |
Example request:
POST /_matrix/client/r0/rooms/%21oldroom%3Aexample.org/upgrade HTTP/1.1 Content-Type: application/json { "new_version": "2" }
Responses:
Status code 200:
The room was successfully upgraded.
Example
{ "replacement_room": "!newroom:example.org" }
Status code 400:
The request was invalid. One way this can happen is if the room version requested is not supported by the homeserver.
Example
{ "errcode": "M_UNSUPPORTED_ROOM_VERSION", "error": "This server does not support that room version" }
Status code 403:
The user is not permitted to upgrade the room.
Example
{ "errcode": "M_FORBIDDEN", "error": "You cannot upgrade this room" }
When the client requests to upgrade a known room to a known version, the server:
Checks that the user has permission to send m.room.tombstone events in the room.
Creates a replacement room with a m.room.create event containing a predecessor field and the applicable room_version.
Replicates transferable state events to the new room. The exact details for what is transferred is left as an implementation detail, however the recommended state events to transfer are:
Membership events should not be transferred to the new room due to technical limitations of servers not being able to impersonate people from other homeservers. Additionally, servers should not transfer state events which are sensitive to who sent them, such as events outside of the Matrix namespace where clients may rely on the sender to match certain criteria.
Moves any local aliases to the new room.
Sends a m.room.tombstone event to the old room to indicate that it is not intended to be used any further.
If possible, the power levels in the old room should also be modified to prevent sending of events and inviting new users. For example, setting events_default and invite to the greater of 50 and users_default + 1.
When a user joins the new room, the server should automatically transfer/replicate some of the user's personalized settings such as notifications, tags, etc.
Homeserver hosts often want to send messages to users in an official capacity, or have resource limits which affect a user's ability to use the homeserver. For example, the homeserver may be limited to a certain number of active users per month and has exceeded that limit. To communicate this failure to users, the homeserver would use the Server Notices room.
The aesthetics of the room (name, topic, avatar, etc) are left as an implementation detail. It is recommended that the homeserver decorate the room such that it looks like an official room to users.
Notices are sent to the client as normal m.room.message events with a msgtype of m.server_notice in the server notices room. Events with a m.server_notice msgtype outside of the server notice room must be ignored by clients.
The specified values for server_notice_type are:
m.server_notice.usage_limit_reached: | |||||
---|---|---|---|---|---|
The server has exceeded some limit which requires the server administrator to intervene. The limit_type describes the kind of limit reached. The specified values for limit_type are:
|
Message Event
Represents a server notice for a user.
Content Key | Type | Description |
---|---|---|
body | string | Required. A human-readable description of the notice. |
msgtype | string | Required. Must be 'm.server_notice'. |
server_notice_type | string | Required. The type of notice being represented. |
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. |
limit_type | string | The kind of usage limit the server has exceeded. Required if the notice type is m.server_notice.usage_limit_reached. |
Example:
{ "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 } }
Clients can identify the server notices room by the m.server_notice tag on the room. Active notices are represented by the pinned events in the server notices room. Server notice events pinned in that room should be shown to the user through special UI and not through the normal pinned events interface in the client. For example, clients may show warning banners or bring up dialogs to get the user's attention. Events which are not server notice events and are pinned in the server notices room should be shown just like any other pinned event in a room.
The client must not expect to be able to reject an invite to join the server notices room. Attempting to reject the invite must result in a M_CANNOT_LEAVE_SERVER_NOTICE_ROOM error. Servers should not prevent the user leaving the room after joining the server notices room, however the same error code must be used if the server will prevent leaving the room.
Servers should manage exactly 1 server notices room per user. Servers must identify this room to clients with the m.server_notice tag. Servers should invite the target user rather than automatically join them to the server notice room.
How servers send notices to clients, and which user they use to send the events, is left as an implementation detail for the server.