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.0.0
This is the first release of the client-server specification. It is largely a dump of what has currently been implemented, and there are several inconsistencies.
An upcoming minor release will deprecate many of these inconsistencies, and they will be removed in the next major release.
Since the draft stage, the following major changes have been made:
For the full historical changelog, see https://github.com/matrix-org/matrix-doc/blob/main/changelogs/legacy/client_server.rst
If this is an unstable snapshot, any changes since the last release may be viewed using git log.
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.
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.
Some standard error codes are below:
M_FORBIDDEN: | Forbidden access, e.g. joining a room without permission, failed login. |
---|---|
M_UNKNOWN_TOKEN: | |
The access token specified was not recognised. | |
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. |
Some requests have unique error codes:
M_USER_IN_USE: | Encountered when trying to register a user ID which has been taken. |
---|---|
M_ROOM_IN_USE: | Encountered when trying to create a room which has been taken. |
M_BAD_PAGINATION: | |
Encountered when specifying bad pagination query parameters. |
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.
Most API endpoints require the user to identify themselves by presenting previously obtained credentials in the form of an access_token query parameter.
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.
Some API endpoints such as login or register 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, where at each stage the client submits a set of data for a given stage 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.
Authentication works by client and server exchanging dictionaries. This specification covers how this is done over JSON HTTP POST.
For each endpoint, a server offers one of more 'flows' that the client can use to authenticate itself. Each flow comprises one or more 'stages'. Flows may have more than one stage to implement n-factor auth. When all stages are complete, authentication is complete and the API call succeeds. To establish what flows a server supports for an endpoint, a client sends the request with no authentication. 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. The homeserver returns a response with HTTP status 401 and a JSON object as follows:
{ "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 one of the stages. It does this by resubmitting the same request with the 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 stage type that the client is attempting to complete. It must also contains 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 stage type being attempted. For example, if the client is attempting to complete login type example.type.foo, it might submit something like this:
{ "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 stage type the client has completed successfully:
{ "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 homeserver decides the attempt was unsuccessful, it returns an error message in the standard format:
{ "errcode": "M_EXAMPLE_ERROR", "error": "Something was wrong" }
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 login type.
If the client has completed all stages of a flow, the homeserver performs the API call and returns the result as normal.
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 login stage type in the 'completed' array indicating whether that stage is complete.
At a high level, the requests made for an API call completing an auth flow with three stages will resemble the following diagram:
_______________________ | Stage 1 | | type: "<stage type1>" | | ___________________ | | |_Request_1_________| | <-- Returns "session" key which is used throughout. | ___________________ | | |_Request_2_________| | |_______________________| | | _________V_____________ | Stage 2 | | type: "<stage type2>" | | ___________________ | | |_Request_1_________| | | ___________________ | | |_Request_2_________| | | ___________________ | | |_Request_3_________| | |_______________________| | | _________V_____________ | Stage 3 | | type: "<stage type3>" | | ___________________ | | |_Request_1_________| | <-- Returns API response |_______________________|
Type: | m.login.password |
---|---|
Description: | The client submits a username and secret password, both sent in plain-text. |
To respond to this type, reply with an auth dict as follows:
{ "type": "m.login.password", "user": "<user_id or user localpart>", "password": "<password>" }
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.
Type: | m.login.recaptcha |
---|---|
Description: | The user completes a Google ReCaptcha 2.0 challenge |
To respond to this type, reply with an auth dict as follows:
{ "type": "m.login.recaptcha", "response": "<captcha response>" }
Type: | m.login.token |
---|---|
Description: | The client submits a username and token. |
To respond to this type, reply with an auth dict as follows:
{ "type": "m.login.token", "user": "<user_id or user localpart>", "token": "<token>", "txn_id": "<client generated nonce>" }
The nonce should be a random string generated by the client for the request. The same nonce should be used if retrying the request.
There are many ways a client may receive a token, including via an email or from an existing logged in device.
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 token must be a macaroon.
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. |
Prior to submitting this, the client should authenticate with an identity server. After authenticating, the session information should be submitted to the homeserver.
To respond to this type, reply with 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'>" } ] }
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. |
To respond to this type, reply with an auth dict with just the type and session, if provided:
{ "type": "m.login.dummy", }
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/<stage type>/fallback/web?session=<session ID>
Where stage 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 attempt to call the JavaScript function window.onAuthDone when the authentication has been completed.
Register for an account on this homeserver.
There are two kinds of user account:
Rate-limited: | Yes. |
---|
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 | ||
username | string | The local part of the desired Matrix ID. If omitted, the homeserver MUST generate a Matrix ID local part. |
bind_email | boolean | If true, the server binds the email used for authentication to the Matrix ID with the ID Server. |
password | string | Required. The desired password for the account. |
Response format:
Parameter | Type | Description |
---|---|---|
access_token | string | An access token for the account. This access token can then be used to authorize other requests. The access token may expire at some point, and if so, it SHOULD come with a refresh_token. There is no specific error message to indicate that a request has failed because an access token has expired; instead, if a client has reason to believe its access token is valid, and it receives an auth error, they should attempt to refresh for a new token on failure, and retry the request with the new token. |
home_server | string | The hostname of the homeserver on which the account has been registered. |
refresh_token | string | (optional) A refresh_token may be exchanged for a new access_token using the /tokenrefresh API endpoint. |
user_id | string | The fully-qualified Matrix ID that has been registered. |
Example request:
POST /_matrix/client/r0/register?kind=guest HTTP/1.1 Content-Type: application/json { "username": "cheeky_monkey", "password": "ilovebananas", "bind_email": false }
Responses:
Status code 200:
The account has been registered.
Example
{ "user_id": "@cheeky_monkey:matrix.org", "access_token": "abc123", "home_server": "matrix.org", "refresh_token": "def456" }
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." }
Authenticates the user by password, and issues an access token they can use to authorize themself in subsequent requests.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
password | string | Required. The user's password. |
type | string | Required. The login type being used. Currently only "m.login.password" is supported. |
user | string | Required. The fully qualified user ID or just local part of the user ID, to log in. |
Response format:
Parameter | Type | Description |
---|---|---|
access_token | string | An access token for the account. This access token can then be used to authorize other requests. The access token may expire at some point, and if so, it SHOULD come with a refresh_token. There is no specific error message to indicate that a request has failed because an access token has expired; instead, if a client has reason to believe its access token is valid, and it receives an auth error, they should attempt to refresh for a new token on failure, and retry the request with the new token. |
home_server | string | The hostname of the homeserver on which the account has been registered. |
refresh_token | string | (optional) A refresh_token may be exchanged for a new access_token using the /tokenrefresh API endpoint. |
user_id | string | The fully-qualified Matrix ID that has been registered. |
Example request:
POST /_matrix/client/r0/login HTTP/1.1 Content-Type: application/json { "type": "m.login.pasword", "user": "cheeky_monkey", "password": "ilovebananas" }
Responses:
Status code 200:
The user has been authenticated.
Example
{ "user_id": "@cheeky_monkey:matrix.org", "access_token": "abc123", "home_server": "matrix.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"}
Exchanges a refresh token for a new access token. This is intended to be used if the access token has expired.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
refresh_token | string | Required. The refresh token which was issued by the server. |
Response format:
Parameter | Type | Description |
---|---|---|
access_token | string | An access token for the account. This access token can then be used to authorize other requests. The access token may expire at some point, and if so, it SHOULD come with a refresh_token. |
refresh_token | string | (optional) A refresh_token may be exchanged for a new access_token using the TODO Linkify /tokenrefresh API endpoint. |
Example request:
POST /_matrix/client/r0/tokenrefresh HTTP/1.1 Content-Type: application/json { "refresh_token": "a1b2c3" }
Responses:
Status code 200:
The refresh token was accepted, and a new access token has been issued. The passed refresh token is no longer valid and cannot be used. A new refresh token will have been returned unless some policy does not allow the user to continue to renew their session.
Example
{ "access_token": "bearwithme123", "refresh_token": "exchangewithme987" }
Status code 403:
The exchange attempt failed. For example, the refresh token may have already been used.
Example
{"errcode": "M_FORBIDDEN"}
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.
Request:
POST /_matrix/client/r0/account/password
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.
The body of the POST request is a JSON object containing:
On success, an empty JSON object is returned.
The error code M_NOT_FOUND is returned if the user authenticated with a third party identifier but the homeserver could not find a matching account in its database.
A homeserver may keep some contact information for administrative use. This is independent of any information kept by any Identity Servers.
Adds contact information to the user's account.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
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. |
threePidCreds | object | Required. The third party credentials to associate with the account. |
threePidCreds.client_secret | string | Required. The client secret used in the session with the Identity Server. |
threePidCreds.id_server | string | Required. The Identity Server to use. |
threePidCreds.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 { "threePidCreds": { "id_server": "matrix.org", "sid": "abc123987", "client_secret": "d0n'tT3ll" }, "bind": false }
Responses:
Status code 200:
The addition was successful.
Example
{}
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." }
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.
Requires auth: | Yes. |
---|
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
threepids | [Third party identifier] |
Third party identifier
Parameter | Type | Description |
---|---|---|
address | string | The third party identifier address. |
medium | string | The medium of the third party identifier. Must be 'email'. |
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" } ] }
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 | ||
new_password | string | Required. The new password for the account. |
Example request:
POST /_matrix/client/r0/account/password HTTP/1.1 Content-Type: application/json { "new_password": "ihatebananas" }
Response:
Status code 200:
The password has been changed.
Example
{}
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 underlying API which is used to to give clients a consistent way of selecting subsets of a potentially changing dataset. Requests pass in from, to, dir and limit parameters which describe where to read from the stream. from and to are opaque textual 'stream tokens' which describe the current position in the dataset. The dir parameter is an enum representing the direction of events to return: either f orwards or b ackwards. The response returns new start and end stream token values which can then be passed to subsequent requests to continue pagination. Not all endpoints will make use of all the parameters outlined here: see the specific endpoint in question for more information.
'START' and 'END' are placeholder values used in these examples to describe the start and end of the dataset respectively.
Unless specified, the default pagination parameters are from=START, to=END, without a limit set.
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 to pagination requests MUST follow the format:
{ "chunk": [ ... , Responses , ... ], "start" : $streamtoken, "end" : $streamtoken }
Where $streamtoken is an opaque token which can be used in another query to get the next set of results. The "start" and "end" keys can only be omitted if the complete dataset is provided in "chunk".
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.
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.
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. |
Response format:
Parameter | Type | Description |
---|---|---|
filter_id | string | The ID of the filter that was created. |
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
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. |
Example request:
GET /_matrix/client/r0/user/%40alice%3Aexample.com/filter/66696p746572 HTTP/1.1
Response:
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"] }
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]->[E6]->[E7]->[E8]->[E9]
Clients can add to the stream by PUTing message or state events, and can read from the stream via the /initialSync, /events, /rooms/<room_id>/initialSync, and /rooms/<room_id>/messages APIs.
For reading events, the intended flow of operation is to call /_matrix/client/r0/initialSync, which returns all of the state and the last N events in the event stream for each room, including start and end values describing the pagination of each room's event stream. For instance, /_matrix/client/r0/initialSync?limit=5 might return the events for a room in the rooms[0].messages.chunk[] array, with tokens describing the start and end of the range in rooms[0].messages.start as '1-2-3' and rooms[0].messages.end as 'a-b-c'.
You can visualise the range of events being returned as:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9] ^ ^ | | start: '1-2-3' end: 'a-b-c'
Now, to receive future events in real-time on the event stream, you simply GET /_matrix/client/r0/events with a from parameter of 'a-b-c': in other words passing in the end token returned by initial sync. The request blocks until new events are available or until your specified timeout elapses, and then returns a new paginatable chunk of events alongside new start and end parameters:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10] ^ ^ | | | end: 'x-y-z' start: 'a-b-c'
To resume polling the events stream, you pass in the new end token as the from parameter of /_matrix/client/r0/events and poll again.
Similarly, to paginate events backwards in order to lazy-load in previous history from the room, you simply GET /_matrix/client/r0/rooms/<room_id>/messages specifying the from token to paginate backwards from and a limit of the number of messages to retrieve. For instance, calling this API with a from parameter of '1-2-3' and a limit of 5 would return:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10] ^ ^ | | start: 'u-v-w' end: '1-2-3'
To continue paginating backwards, one calls the /messages API again, supplying the new start value as the from parameter.
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.
Clients receive new events by "long-polling" the homeserver via the events API. This involves specifying a timeout in the request which will hold open the HTTP connection for a short period of time waiting for new events, returning early if an event occurs. Only the events API supports long-polling. All events which are visible to the client will appear in the events API. When the request returns, an end token is included in the response. This token can be used in the next request to continue where the last request left off. Multiple events can be returned per long-poll.
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.
When the client first logs in, they will need to initially synchronise with their homeserver. This is achieved via the initial sync API described below. This API also returns an end token which can be used with the event stream.
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.
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 |
---|---|---|
chunk | [Event] | An array of events. |
end | string | A token which correlates to the last value in chunk. This token should be used in the next request to /events. |
start | string | A token which correlates to the first value in chunk. This is usually the same token supplied to from=. |
Event
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
UnsignedData
Parameter | Type | Description |
---|---|---|
age | integer | The time in milliseconds that has elapsed since the event was sent |
redacted_because | string | The reason this event was redacted, if it was redacted |
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
Response:
Status code 200:
The events received, which may be none.
Example
{ "start": "s3456_9_0", "end": "s3457_9_0", "chunk": [ { "age": 32, "content": { "body": "incoming message", "msgtype": "m.text" }, "event_id": "$14328055551tzaee:localhost", "origin_server_ts": 1432804485886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "sender": "@bob:localhost" } ] }
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.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
eventId | string | Required. The event ID to get. |
Example request:
GET /_matrix/client/r0/events/%24asfDuShaf7Gafaw%3Amatrix.org HTTP/1.1
Response:
Status code 200:
The full event.
Example
{ "content": { "body": "Hello world!", "msgtype": "m.text" }, "room_id:": "!wfgy43Sg4a:matrix.org", "sender": "@bob:matrix.org", "event_id": "$asfDuShaf7Gafaw:matrix.org", "type": "m.room.message" }
This returns the full state for this user, with an optional limit on the number of messages per room to return.
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 | 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] | A list of presence events. |
rooms | [RoomInfo] |
RoomInfo
Parameter | Type | Description |
---|---|---|
account_data | [Event] | The private data that this user has attached to this room. |
invite | InviteEvent | The invite event if membership is invite |
membership | enum | The user's membership state in this room. One of: ["invite", "join", "leave", "ban"] |
messages | PaginationChunk | The pagination chunk for this room. |
room_id | string | The ID of 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"] |
Event
Parameter | Type | Description |
---|---|---|
content | EventContent | 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 | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
InviteEvent
Parameter | Type | Description |
---|---|---|
content | EventContent | |
event_id | string | Required. The globally unique event identifier. |
invite_room_state | [StrippedState] | A subset of the state of the room at the time of the invite, if membership is invite |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
state_key | string | The user_id this membership event relates to. |
type | string | Must be 'm.room.member'. |
unsigned | UnsignedData | Contains optional extra information about the event. |
EventContent
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 | The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] |
third_party_invite | Invite |
Invite
Parameter | Type | Description |
---|---|---|
signed | signed | A block of content which has been signed, which servers can use to verify the event. Clients should ignore this. |
signed
Parameter | Type | Description |
---|---|---|
mxid | string | The invited matrix user ID. Must be equal to the user_id property of the event. |
signatures | Signatures | A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API. |
token | string | The token property of the containing third_party_invite object. |
StrippedState
Parameter | Type | Description |
---|---|---|
content | EventContent | The content for the event. |
state_key | string | The state_key for the event. |
type | enum | The type for the event. One of: ["m.room.join_rules", "m.room.canonical_alias", "m.room.avatar", "m.room.name"] |
PaginationChunk
Parameter | Type | Description |
---|---|---|
chunk | [RoomEvent] | 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. |
end | string | A token which correlates to the last value in chunk. Used for pagination. |
start | string | A token which correlates to the first value in chunk. Used for pagination. |
RoomEvent
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
StateEvent
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
state_key | string | 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. The key MUST NOT start with '_'. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
UnsignedData
Parameter | Type | Description |
---|---|---|
age | integer | The time in milliseconds that has elapsed since the event was sent |
redacted_because | string | The reason this event was redacted, if it was redacted |
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/initialSync?limit=2&archived=true HTTP/1.1
Response:
Status code 200:
The user's current state.
Example
{ "end": "s3456_9_0", "presence": [ { "content": { "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "last_active_ago": 31053, "presence": "online", "user_id": "@bob:localhost" }, "type": "m.presence" } ], "account_data": [ { "type": "org.example.custom.config", "content": { "custom_config_key": "custom_config_value" } } ], "rooms": [ { "membership": "join", "messages": { "chunk": [ { "age": 343513403, "content": { "body": "foo", "msgtype": "m.text" }, "event_id": "$14328044851tzTJS:localhost", "origin_server_ts": 1432804485886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "sender": "@alice:localhost" }, { "age": 343511809, "content": { "body": "bar", "msgtype": "m.text" }, "event_id": "$14328044872spjFg:localhost", "origin_server_ts": 1432804487480, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "sender": "@bob:localhost" } ], "end": "s3456_9_0", "start": "t44-3453_9_0" }, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state": [ { "age": 7148266897, "content": { "join_rule": "public" }, "event_id": "$14259997323TLwtb:localhost", "origin_server_ts": 1425999732392, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.join_rules", "sender": "@alice:localhost" }, { "age": 6547561012, "content": { "avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto", "membership": "join" }, "event_id": "$1426600438280zExKY:localhost", "membership": "join", "origin_server_ts": 1426600438277, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "@alice:localhost", "type": "m.room.member", "sender": "@alice:localhost" }, { "age": 7148267200, "content": { "creator": "@alice:localhost" }, "event_id": "$14259997320KhbwJ:localhost", "origin_server_ts": 1425999732089, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.create", "sender": "@alice:localhost" }, { "age": 1622568720, "content": { "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:localhost", "origin_server_ts": 1431525430569, "replaces_state": "$142652023736BSXcM:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "@bob:localhost", "type": "m.room.member", "sender": "@bob:localhost" }, { "age": 7148267004, "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "kick": 50, "redact": 50, "state_default": 50, "users": { "@alice:localhost": 100 }, "users_default": 0 }, "event_id": "$14259997322mqfaq:localhost", "origin_server_ts": 1425999732285, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.power_levels", "sender": "@alice:localhost" } ], "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" } } ] } ] }
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.
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 enocoded 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. |
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. One of: ["offline"] |
timeout | integer | The maximum time to poll in milliseconds before returning this request. |
Response format:
Parameter | Type | Description |
---|---|---|
next_batch | string | The batch token to supply in the since param of the next /sync request. |
presence | Presence | The updates to the presence status of other users. |
rooms | Rooms | Updates to rooms. |
Presence
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events |
Rooms
Parameter | Type | Description |
---|---|---|
invite | {string: Invited Room} | The rooms that the user has been invited to. |
join | {string: Joined Room} | The rooms that the user has joined. |
leave | {string: Left Room} | The rooms that the user has left or been banned from. |
Invited 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. |
InviteState
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events |
Joined Room
Parameter | Type | Description |
---|---|---|
account_data | Account Data | The private data that this user has attached to this room. |
ephemeral | Ephemeral | The ephemeral events in the room that aren't recorded in the timeline or state of the room. e.g. typing. |
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). |
timeline | Timeline | The timeline of messages and state changes in the room. |
Account Data
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events |
Ephemeral
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events |
Left Room
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. |
State
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events |
Timeline
Parameter | Type | Description |
---|---|---|
events | [Event] | List of events |
limited | boolean | True if the number of events returned was limited by the limit on the filter |
prev_batch | string | If the batch was limited then this is a token that can be supplied to the server to retrieve earlier events |
Event
Parameter | Type | Description |
---|---|---|
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 |
Unsigned
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. |
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": [ { "sender": "@alice:example.com", "type": "m.presence", "content": {"presence": "online"} } ] }, "account_data": { "events": [ { "type": "org.example.custom.config", "content": { "custom_config_key": "custom_config_value" } } ] }, "rooms": { "join": { "!726s6s6q:example.com": { "state": { "events": [ { "sender": "@alice:example.com", "type": "m.room.member", "state_key": "@alice:example.com", "content": {"membership": "join"}, "origin_server_ts": 1417731086795, "event_id": "$66697273743031:example.com" } ] }, "timeline": { "events": [ { "sender": "@bob:example.com", "type": "m.room.member", "state_key": "@bob:example.com", "content": {"membership": "join"}, "prev_content": {"membership": "invite"}, "origin_server_ts": 1417731086795, "event_id": "$7365636s6r6432:example.com" }, { "sender": "@alice:example.com", "type": "m.room.message", "age": 124524, "txn_id": "1234", "content": { "body": "I am a fish", "msgtype": "m.text" }, "origin_server_ts": 1417731086797, "event_id": "$74686972643033:example.com" } ], "limited": true, "prev_batch": "t34-23535_0_0" }, "ephemeral": { "events": [ { "type": "m.typing", "content": {"user_ids": ["@alice:example.com"]} } ] }, "account_data": { "events": [ { "type": "m.tag", "content": {"tags": {"work": {"order": 1}}} }, { "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": {} } }
There are several APIs provided to GET events for a room:
Get a copy of the current state and the most recent messages in a room.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get the data. |
Response format:
RoomInfo
Parameter | Type | Description |
---|---|---|
account_data | [Event] | The private data that this user has attached to 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. |
room_id | string | The ID of 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"] |
Event
Parameter | Type | Description |
---|---|---|
content | EventContent | 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 | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
PaginationChunk
Parameter | Type | Description |
---|---|---|
chunk | [RoomEvent] | 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. |
end | string | A token which correlates to the last value in chunk. Used for pagination. |
start | string | A token which correlates to the first value in chunk. Used for pagination. |
RoomEvent
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
StateEvent
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
state_key | string | 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. The key MUST NOT start with '_'. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
UnsignedData
Parameter | Type | Description |
---|---|---|
age | integer | The time in milliseconds that has elapsed since the event was sent |
redacted_because | string | The reason this event was redacted, if it was redacted |
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/initialSync HTTP/1.1
Response:
Status code 200:
The current state of the room
Example
{ "membership": "join", "messages": { "chunk": [ { "age": 343513403, "content": { "body": "foo", "msgtype": "m.text" }, "event_id": "$14328044851tzTJS:example.com", "origin_server_ts": 1432804485886, "room_id": "!636q39766251:example.com", "type": "m.room.message", "sender": "@alice:example.com" }, { "age": 343511809, "content": { "body": "bar", "msgtype": "m.text" }, "event_id": "$14328044872spjFg:example.com", "origin_server_ts": 1432804487480, "room_id": "!636q39766251:example.com", "type": "m.room.message", "sender": "@bob:example.com" } ], "end": "s3456_9_0", "start": "t44-3453_9_0" }, "room_id": "!636q39766251:example.com", "state": [ { "age": 7148266897, "content": { "join_rule": "public" }, "event_id": "$14259997323TLwtb:example.com", "origin_server_ts": 1425999732392, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.join_rules", "sender": "@alice:example.com" }, { "age": 6547561012, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", "membership": "join", "origin_server_ts": 1426600438277, "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", "sender": "@alice:example.com" }, { "age": 7148267200, "content": { "creator": "@alice:example.com" }, "event_id": "$14259997320KhbwJ:example.com", "origin_server_ts": 1425999732089, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.create", "sender": "@alice:example.com" }, { "age": 1622568720, "content": { "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:example.com", "origin_server_ts": 1431525430569, "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", "sender": "@bob:example.com" }, { "age": 7148267004, "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "kick": 50, "redact": 50, "state_default": 50, "users": { "@alice:example.com": 100 }, "users_default": 0 }, "event_id": "$14259997322mqfaq:example.com", "origin_server_ts": 1425999732285, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.power_levels", "sender": "@alice:example.com" } ], "visibility": "private", "account_data": [{ "type": "m.tag", "content": {"tags": {"work": {"order": "1"}}} }] }
Get the list of members for this room.
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to get the member events for. |
Response format:
Parameter | Type | Description |
---|---|---|
chunk | [MemberEvent] |
MemberEvent
Parameter | Type | Description |
---|---|---|
content | EventContent | |
event_id | string | Required. The globally unique event identifier. |
invite_room_state | [StrippedState] | A subset of the state of the room at the time of the invite, if membership is invite |
prev_content | EventContent | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
state_key | string | The user_id this membership event relates to. |
type | string | Must be 'm.room.member'. |
unsigned | UnsignedData | Contains optional extra information about the event. |
EventContent
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 | The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] |
third_party_invite | Invite |
Invite
Parameter | Type | Description |
---|---|---|
signed | signed | A block of content which has been signed, which servers can use to verify the event. Clients should ignore this. |
signed
Parameter | Type | Description |
---|---|---|
mxid | string | The invited matrix user ID. Must be equal to the user_id property of the event. |
signatures | Signatures | A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API. |
token | string | The token property of the containing third_party_invite object. |
StrippedState
Parameter | Type | Description |
---|---|---|
content | EventContent | The content for the event. |
state_key | string | The state_key for the event. |
type | enum | The type for the event. One of: ["m.room.join_rules", "m.room.canonical_alias", "m.room.avatar", "m.room.name"] |
UnsignedData
Parameter | Type | Description |
---|---|---|
age | integer | The time in milliseconds that has elapsed since the event was sent |
redacted_because | string | The reason this event was redacted, if it was redacted |
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 HTTP/1.1
Response:
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 te room then this will be the members of the room when you left.
Example
{ "chunk": [ { "age": 6547561012, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", "membership": "join", "origin_server_ts": 1426600438277, "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", "sender": "@alice:example.com" }, { "age": 1622568720, "content": { "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:example.com", "origin_server_ts": 1431525430569, "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", "sender": "@bob:example.com" } ] }
Get the state events for the current state of a room.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room to look up the state for. |
Response format:
RoomState
Parameter | Type | Description |
---|---|---|
N/A | [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. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/state HTTP/1.1
Response:
Status code 200:
The current state of the room
Example
[ { "age": 7148266897, "content": { "join_rule": "public" }, "event_id": "$14259997323TLwtb:example.com", "origin_server_ts": 1425999732392, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.join_rules", "sender": "@alice:example.com" }, { "age": 6547561012, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", "membership": "join", "origin_server_ts": 1426600438277, "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", "sender": "@alice:example.com" }, { "age": 7148267200, "content": { "creator": "@alice:example.com" }, "event_id": "$14259997320KhbwJ:example.com", "origin_server_ts": 1425999732089, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.create", "sender": "@alice:example.com" }, { "age": 1622568720, "content": { "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:example.com", "origin_server_ts": 1431525430569, "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", "sender": "@bob:example.com" }, { "age": 7148267004, "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "kick": 50, "redact": 50, "state_default": 50, "users": { "@alice:example.com": 100 }, "users_default": 0 }, "event_id": "$14259997322mqfaq:example.com", "origin_server_ts": 1425999732285, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.power_levels", "sender": "@alice:example.com" } ]
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.
This looks up the state event with the empty state key.
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. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/state/m.room.name HTTP/1.1
Response:
Status code 200:
The content of the state event.
Example
{"name": "Example room name"}
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.
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. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/state/m.room.name/ HTTP/1.1
Response:
Status code 200:
The content of the state event.
Example
{"name": "Example room name"}
This API returns a list of message and state events for a room. It uses pagination query parameters to paginate history in the room.
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 the initial sync API. |
dir | enum | Required. The direction to return events from. One of: ["b", "f"] |
limit | integer | The maximum number of events to return. Default: 10. |
Response format:
Parameter | Type | Description |
---|---|---|
chunk | [RoomEvent] | A list of room events. |
end | string | The token the pagination ends at. If dir=b this token should be used again to request even earlier events. |
start | string | The token to start paginating from. If dir=b this will be the token supplied in from. |
Example request:
GET /_matrix/client/r0/rooms/%21636q39766251%3Aexample.com/messages?from=s345_678_333&dir=b&limit=3 HTTP/1.1
Response:
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": [ { "origin_server_ts": 1444812213737, "user_id": "@alice:example.com", "event_id": "$1444812213350496Caaaa:example.com", "content": { "body": "hello world", "msgtype":"m.text" }, "room_id":"!Xq3620DUiqCaoxq:example.com", "type":"m.room.message", "age": 1042 }, { "origin_server_ts": 1444812194656 , "user_id": "@bob:example.com", "event_id": "$1444812213350496Cbbbb:example.com", "content": { "body": "the world is big", "msgtype":"m.text" }, "room_id":"!Xq3620DUiqCaoxq:example.com", "type":"m.room.message", "age": 20123 }, { "origin_server_ts": 1444812163990, "user_id": "@bob:example.com", "event_id": "$1444812213350496Ccccc:example.com", "content": { "name": "New room name" }, "prev_content": { "name": "Old room name" }, "state_key": "", "room_id":"!Xq3620DUiqCaoxq:example.com", "type":"m.room.name", "age": 50789 } ] }
State events can be sent using this endpoint. These events will be overwritten if <room id>, <event type> and <state key> all match. This endpoint forces the state key to be the empty string.
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.
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. |
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.name HTTP/1.1 Content-Type: application/json { "name": "New name for the room" }
Response:
Status code 200:
An ID for the sent event.
Example
{ "event_id": "YUwRidLecu" }
State events can be sent using this endpoint. This endpoint is equivalent to calling /rooms/{roomId}/state/{eventType}/{stateKey} with an empty stateKey. Previous state events with matching <roomId> and <eventType>, and empty <stateKey>, will be overwritten.
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.
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. |
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.name/ HTTP/1.1 Content-Type: application/json { "name": "New name for the room" }
Response:
Status code 200:
An ID for the sent event.
Example
{ "event_id": "YUwRidLecu" }
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%3Adomain.com { "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.
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 a unique ID; 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" }
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 redaction event should be added under the key redacted_because. When a client receives a redaction event it should change the redacted event in the same way a server does.
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:
{ "age": 242352, "content": { "reason": "Spamming" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "redacts": "!fukweghifu23:localhost", "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.redaction" }
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.
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/api/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" }
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:
levels for various actions within the room such as sending events.
m.room.join_rules : Whether the room is "invite-only" or not.
See Room Events for more information on these events. To create a room, a client has to use the the following API.
Create a new room with various configuration options.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
invite | array[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. |
visibility | string | A public visibility indicates that the room will be shown in the published room list. A private visibility will hide the room from the published room list. Rooms default to private visibility if this key is not included. NB: This should not be confused with join_rules which also uses the word public. |
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. |
preset | string | Convenience parameter for setting various default state events based on a preset. Must be either: private_chat => join_rules is set to invite. history_visibility is set to shared. trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the room creator. public_chat: => join_rules is set to public. history_visibility is set to shared. |
creation_content | object | Extra keys to be added to the content of the m.room.create. The server will clober the following keys: creator. Future versions of the specification may allow the server to clobber other keys. |
initial_state | array[object] | 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 presets, but gets overriden by name and topic keys. |
initial_state[0].content | string | |
initial_state[0].state_key | string | |
initial_state[0].type | string | |
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. |
Response format:
Parameter | Type | Description |
---|---|---|
room_id | string | 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 } }
Response:
Status code 200:
Information about the newly created room.
Example
{ "room_id": "!sefiuhWgwghwWgh:example.com" }
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.
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.
Homeservers can respond to resolve requests for aliases on other domains than their own by using the federation API to ask other domain name homeservers.
Create a new mapping from room alias to room ID.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomAlias | string | Required. The room alias to set. |
JSON body parameters | ||
room_id | string | 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" }
Response:
Status code 200:
The mapping was created.
Example
{}
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.
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
Response:
Status code 200:
The mapping was deleted.
Example
{}
Get the room ID corresponding to this room alias.
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 ID. |
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 409:
A room alias with that name already exists.
Example
{ "errcode": "M_UNKNOWN", "error": "Room alias #monkeys:matrix.org already exists." }
Status code 404:
There is no mapped room ID for this room alias.
Example
{ "errcode": "M_NOT_FOUND", "error": "Room ID !abnjk1jdasj98:capuchins.com 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.
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:
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 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"}
/_matrix/client/r0/join/{roomId} is an alias for /_matrix/client/r0/rooms/{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 API.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
roomId | string | Required. The room identifier or room alias to join. |
Example request:
POST /_matrix/client/r0/rooms/%23monkeys%3Amatrix.org/join HTTP/1.1
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."}
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 until they are unbanned.
The caller must have the required power level in order to perform this operation.
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 | ||
reason | string | The reason the user has been banned. |
user_id | string | Required. The fully qualified user ID of the user being banned. |
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." }
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 on the /initialSync API.
Whether or not they actually joined the room, if the room is an "invite-only" room they will need to be re-invited before they can re-join the room.
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 will implicitly leave the room as part of this API call.
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
Response:
Status code 200:
The room has been forgotten.
Example
{}
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
Response:
Status code 200:
The room has been left.
Example
{}
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 and adjusts the power level of this event to a level higher than the banned person. 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" }
Lists the public rooms on the server.
This API returns paginated responses.
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
chunk | [PublicRoomsChunk] | A paginated chunk of public rooms. |
end | string | A pagination token for the response. |
start | string | A pagination token for the response. |
PublicRoomsChunk
Parameter | Type | Description |
---|---|---|
aliases | [string] | Aliases of the room. May be empty. |
guest_can_join | boolean | 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. |
name | string | The name of the room, if any. May be null. |
num_joined_members | number | The number of members joined to the room. |
room_id | string | The ID of the room. |
topic | string | The topic of the room, if any. May be null. |
world_readable | boolean | Whether the room may be viewed by guest users without joining. |
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"], "guest_can_join": false, "name": "CHEESE", "num_joined_members": 37, "room_id": "!ol19s:bleecker.street", "topic": "Tasty tasty cheese", "world_readable": true } ], "start": "p190q", "end": "p1902" }
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" }
Response:
Status code 200:
The display name was set.
Example
{}
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.
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. |
Example request:
GET /_matrix/client/r0/profile/%40alice%3Aexample.com/displayname HTTP/1.1
Response:
Status code 200:
The display name for this user.
Example
{ "displayname": "Alice Margatroid" }
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" }
Response:
Status code 200:
The avatar URL was set.
Example
{}
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.
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. |
Example request:
GET /_matrix/client/r0/profile/%40alice%3Aexample.com/avatar_url HTTP/1.1
Response:
Status code 200:
The avatar URL for this user.
Example
{ "avatar_url": "mxc://matrix.org/SDGdghriugerRg" }
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.
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. |
displayname | string | The user's display name if they have set one. |
Example request:
GET /_matrix/client/r0/profile/%40alice%3Aexample.com HTTP/1.1
Response:
Status code 200:
The avatar URL for this user.
Example
{ "avatar_url": "mxc://matrix.org/SDGdghriugerRg", "displayname": "Alice Margatroid" }
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.
All communication in Matrix is expressed in the form of data objects called Events. These are the fundamental building blocks common to the client-server, server-server and application-service APIs, and are described below.
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 | 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 | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
In addition to the Event fields, Room Events may have the following additional fields.
Key | Type | Description |
---|---|---|
event_id | string | Required. The globally unique event identifier. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
unsigned | object | Contains optional extra information about the event. |
In addition to the Room Event fields, State Events have the following additional fields.
Key | Type | Description |
---|---|---|
prev_content | object | Optional. The previous content for this event. If there is no previous content, this key will be missing. |
state_key | string | 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. The key MUST NOT start with '_'. |
The total size of any event MUST NOT exceed 65 KB. 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] | A list of room aliases. |
Example:
{ "age": 242352, "content": { "aliases": [ "#somewhere:localhost", "#another:localhost" ] }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "localhost", "type": "m.room.aliases" }
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.
Content Key | Type | Description |
---|---|---|
alias | string | The canonical alias. |
Example:
{ "age": 242352, "content": { "alias": "#somewhere:localhost" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.canonical_alias" }
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 | 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. |
Example:
{ "age": 242352, "content": { "creator": "@example:localhost" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.create" }
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 | The type of rules used for users wishing to join this room. One of: ["public", "knock", "invite", "private"] |
Example:
{ "age": 242352, "content": { "join_rule": "public" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.join_rules" }
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 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 outside the content key. If present, this contains an array of StrippedState Events. These events provide information on a few select state events such as the room name. EventContent
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 | The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] |
third_party_invite | Invite |
Invite
Invite Key | Type | Description |
---|---|---|
signed | signed | A block of content which has been signed, which servers can use to verify the event. Clients should ignore this. |
signed
signed Key | Type | Description |
---|---|---|
mxid | string | The invited matrix user ID. Must be equal to the user_id property of the event. |
signatures | Signatures | A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API. |
token | string | The token property of the containing third_party_invite object. |
StrippedState
StrippedState Key | Type | Description |
---|---|---|
content | EventContent | The content for the event. |
state_key | string | The state_key for the event. |
type | enum | The type for the event. One of: ["m.room.join_rules", "m.room.canonical_alias", "m.room.avatar", "m.room.name"] |
Examples:
{ "age": 242352, "content": { "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto", "displayname": "Alice Margatroid", "membership": "join" }, "event_id": "$WLGTSEFSEF:localhost", "invite_room_state": [ { "content": { "name": "Forest of Magic" }, "state_key": "", "type": "m.room.name" }, { "content": { "join_rules": "invite" }, "state_key": "", "type": "m.room.join_rules" } ], "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "@alice:localhost", "type": "m.room.member" }
{ "age": 242352, "content": { "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto", "displayname": "Alice Margatroid", "membership": "join" }, "event_id": "$WLGTSEFSEF:localhost", "invite_room_state": [ { "content": { "name": "Forest of Magic" }, "state_key": "", "type": "m.room.name" }, { "content": { "join_rules": "invite" }, "state_key": "", "type": "m.room.join_rules" } ], "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "@alice:localhost", "type": "m.room.member" }
{ "age": 242352, "content": { "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto", "displayname": "Alice Margatroid", "membership": "join", "third_party_invite": { "signed": { "mxid": "@alice:localhost", "signatures": { "magic.forest": { "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" } }, "token": "abc123" } } }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "@alice:localhost", "type": "m.room.member" }
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. 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.
Content Key | Type | Description |
---|---|---|
ban | number | The level required to ban a user. |
events | {string: number} | The level required to send specific event types. This is a mapping from event type to power level required. |
events_default | number | The default level required to send message events. Can be overridden by the events key. |
kick | number | The level required to kick a user. |
redact | number | The level required to redact an event. |
state_default | number | The default level required to send state events. Can be overridden by the events key. |
users | {string: number} | The power levels for specific users. This is a mapping from user_id to power level for that user. |
users_default | number | The default power level for every user in the room, unless their user_id is mentioned in the users key. |
Example:
{ "age": 242352, "content": { "ban": 50, "events": { "m.room.name": 100, "m.room.power_levels": 100 }, "events_default": 0, "kick": 50, "redact": 50, "state_default": 50, "users": { "@example:localhost": 100 }, "users_default": 0 }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.power_levels" }
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:
{ "age": 242352, "content": { "reason": "Spamming" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "redacts": "!fukweghifu23:localhost", "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.redaction" }
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 |
Presence | Required | Required | Required | Required | Optional |
Push Notifications | Optional | Required | Optional | Optional | Optional |
Receipts | Required | Required | Required | Required | Optional |
Typing Notifications | Required | Required | Required | Required | Optional |
VoIP | Required | Required | Required | 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 |
Server Administration | Optional | Optional | Optional | Optional | Optional |
Event Context | 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 | The textual representation of this message. |
msgtype | string | The type of message, e.g. m.image, m.text |
Examples:
{ "age": 242352, "content": { "body": "This is an example notice", "msgtype": "m.notice" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 146, "content": { "body": "something-important.doc", "filename": "something-important.doc", "info": { "mimetype": "application/msword", "size": 46144 }, "msgtype": "m.file", "url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 146, "content": { "body": "Bee Gees - Stayin' Alive", "info": { "duration": 2140786, "mimetype": "audio/mpeg", "size": 1563685 }, "msgtype": "m.audio", "url": "mxc://localhost/ffed755USFFxlgbQYZGtryd" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 146, "content": { "body": "Big Ben, London, UK", "geo_uri": "geo:51.5008,0.1247", "msgtype": "m.location", "thumbnail_info": { "h": 300, "mimetype": "image/jpeg", "size": 46144, "w": 300 }, "thumbnail_url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 242352, "content": { "body": "filename.jpg", "info": { "h": 398, "mimetype": "image/jpeg", "size": 31037, "w": 394 }, "msgtype": "m.image", "url": "mxc://localhost/JWEIFJgwEIhweiWJE" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 242352, "content": { "body": "thinks this is an example emote", "msgtype": "m.emote" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 146, "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://localhost/FHyPlCeYUSFFxlgbQYZmoEoe", "w": 480 }, "msgtype": "m.video", "url": "mxc://localhost/a526eYUSFFxlgbQYZmo442" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
{ "age": 242352, "content": { "body": "This is an example text message", "msgtype": "m.text" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
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 | The event that this feedback is related to. |
type | enum | The type of feedback. One of: ["delivered", "read"] |
Example:
{ "age": 242352, "content": { "target_event_id": "$WEIGFHFW:localhost", "type": "delivered" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message.feedback" }
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. The room name can also be set when creating a room using /createRoom with the name key.
Content Key | Type | Description |
---|---|---|
name | string | The name of the room. This MUST NOT exceed 255 bytes. |
Example:
{ "age": 242352, "content": { "name": "The room name" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.name" }
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 | The topic text. |
Example:
{ "age": 242352, "content": { "topic": "A room topic" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.topic" }
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. |
thumbnail_info | ImageInfo | Metadata about the image referred to in thumbnail_url. |
thumbnail_url | string | The URL to the thumbnail of the image. |
url | string | The URL to the image. |
ImageInfo
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The height of the image in pixels. |
mimetype | string | The mimetype of the image, e.g. image/jpeg. |
size | integer | Size of the image in bytes. |
w | integer | The width of the image in pixels. |
Example:
{ "age": 242352, "content": { "info": { "h": 398, "mimetype": "image/jpeg", "size": 31037, "w": 394 }, "url": "mxc://localhost/JWEIFJgwEIhweiWJE" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.avatar" }
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.
This message is the most basic message and is used to represent text.
Content Key | Type | Description |
---|---|---|
body | string | The body of the message. |
msgtype | string | Must be 'm.text'. |
Example:
{ "age": 242352, "content": { "body": "This is an example text message", "msgtype": "m.text" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
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 | The emote action to perform. |
msgtype | string | Must be 'm.emote'. |
Example:
{ "age": 242352, "content": { "body": "thinks this is an example emote", "msgtype": "m.emote" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
A m.notice message should be considered similar to a plain m.text message except that clients should visually distinguish it in some way. It is intended to be used by automated clients, such as bots, bridges, and other entities, rather than humans. Additionally, such automated agents which watch a room for messages and respond to them ought to ignore m.notice messages. This helps to prevent infinite-loop situations where two automated clients continuously exchange messages, as each responds to the other.
Content Key | Type | Description |
---|---|---|
body | string | The notice text to send. |
msgtype | string | Must be 'm.notice'. |
Example:
{ "age": 242352, "content": { "body": "This is an example notice", "msgtype": "m.notice" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
This message represents a single image and an optional thumbnail.
Content Key | Type | Description |
---|---|---|
body | string | 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 | Must be 'm.image'. |
thumbnail_info | ImageInfo | Metadata about the image referred to in thumbnail_url. |
thumbnail_url | string | The URL to the thumbnail of the image. |
url | string | The URL to the image. |
ImageInfo
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The height of the image in pixels. |
mimetype | string | The mimetype of the image, e.g. image/jpeg. |
size | integer | Size of the image in bytes. |
w | integer | The width of the image in pixels. |
Example:
{ "age": 242352, "content": { "body": "filename.jpg", "info": { "h": 398, "mimetype": "image/jpeg", "size": 31037, "w": 394 }, "msgtype": "m.image", "url": "mxc://localhost/JWEIFJgwEIhweiWJE" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.room.message" }
This message represents a generic file.
Content Key | Type | Description |
---|---|---|
body | string | 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 | Must be 'm.file'. |
thumbnail_info | ImageInfo | Metadata about the image referred to in thumbnail_url. |
thumbnail_url | string | The URL to the thumbnail of the file. |
url | string | The URL to the file. |
FileInfo
FileInfo Key | Type | Description |
---|---|---|
mimetype | string | The mimetype of the file e.g. application/msword. |
size | integer | The size of the file in bytes. |
ImageInfo
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The height of the image in pixels. |
mimetype | string | The mimetype of the image, e.g. image/jpeg. |
size | integer | Size of the image in bytes. |
w | integer | The width of the image in pixels. |
Example:
{ "age": 146, "content": { "body": "something-important.doc", "filename": "something-important.doc", "info": { "mimetype": "application/msword", "size": 46144 }, "msgtype": "m.file", "url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
This message represents a real-world location.
Content Key | Type | Description |
---|---|---|
body | string | 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 | A geo URI representing this location. |
msgtype | string | Must be 'm.location'. |
thumbnail_info | ImageInfo | |
thumbnail_url | string | The URL to a thumbnail of the location being represented. |
ImageInfo
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The height of the image in pixels. |
mimetype | string | The mimetype of the image, e.g. image/jpeg. |
size | integer | Size of the image in bytes. |
w | integer | The width of the image in pixels. |
Example:
{ "age": 146, "content": { "body": "Big Ben, London, UK", "geo_uri": "geo:51.5008,0.1247", "msgtype": "m.location", "thumbnail_info": { "h": 300, "mimetype": "image/jpeg", "size": 46144, "w": 300 }, "thumbnail_url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
This message represents a single video clip.
Content Key | Type | Description |
---|---|---|
body | string | 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 | Must be 'm.video'. |
url | string | The URL to the video clip. |
VideoInfo
VideoInfo Key | Type | Description |
---|---|---|
duration | integer | The duration of the video in milliseconds. |
h | integer | The height of the video in pixels. |
mimetype | string | The mimetype of the video e.g. video/mp4. |
size | integer | The size of the video in bytes. |
thumbnail_info | ImageInfo | |
thumbnail_url | string | The URL to a thumbnail of the video clip. |
w | integer | The width of the video in pixels. |
ImageInfo
ImageInfo Key | Type | Description |
---|---|---|
h | integer | The height of the image in pixels. |
mimetype | string | The mimetype of the image, e.g. image/jpeg. |
size | integer | Size of the image in bytes. |
w | integer | The width of the image in pixels. |
Example:
{ "age": 146, "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://localhost/FHyPlCeYUSFFxlgbQYZmoEoe", "w": 480 }, "msgtype": "m.video", "url": "mxc://localhost/a526eYUSFFxlgbQYZmo442" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
This message represents a single audio clip.
Content Key | Type | Description |
---|---|---|
body | string | 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 | Must be 'm.audio'. |
url | string | The URL to the audio clip. |
AudioInfo
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:
{ "age": 146, "content": { "body": "Bee Gees - Stayin' Alive", "info": { "duration": 2140786, "mimetype": "audio/mpeg", "size": 1563685 }, "msgtype": "m.audio", "url": "mxc://localhost/ffed755USFFxlgbQYZGtryd" }, "event_id": "$143273582443PhrSn:localhost", "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "sender": "@example:localhost", "type": "m.room.message" }
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.
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 cannot be fully avoided in the current client-server API. Two scenarios need to be considered:
In the first scenario, the client will receive an event ID when the request to send the message completes. This ID can be used to identify the duplicate event when it arrives on the event stream. However, in the second scenario, the event arrives before the client has obtained an event ID. This makes it impossible to identify it as a duplicate event. This results in the client displaying the message twice for a fraction of a second before the 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. A future version of the client-server API will resolve this by attaching the transaction ID of the sending request to the event itself.
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:
If the room has an m.room.name state event, use the name given by that event.
If the room has an m.room.canonical_alias state event, use the alias given by that event.
If neither of the above events are present, a name should be composed based on the members of the room. Clients should consider m.room.member events for users other than the logged-in user, with membership: join or membership: invite.
If there is only one such event, the display name for the room should be the disambiguated display name of the corresponding user.
If there are two such events, they should be lexicographically sorted by their state_key (i.e. the corresponding user IDs), and the display name for the room should be the disambiguated display name of both users: "<user1> and <user2>", or a localised variant thereof.
If there are three or more such events, the display name for the room should be based on the disambiguated display name of the user corresponding to the first such event, under a lexicographical sorting according to their state_key. The display name should be in the format "<user1> and <N> others" (or a localised variant thereof), where N is the number of m.room.member events with membership: join or membership: invite, excluding the logged-in user and "user1".
For example, if Alice joins a room, where Bob (whose user id is @superuser:example.com), Carol (user id @carol:example.com) and Dan (user id @dan:matrix.org) are in conversation, Alice's client should show the room name as "Carol and 2 others".
If the room has no m.room.name or m.room.canonical_alias events, and no active members other than the current user, clients should consider m.room.member events with membership: leave. If such events exist, a display name such as "Empty room (was <user1> and <N> others)" (or a localised variant thereof) should be used, following similar rules as for active members (see above).
A complete absence of m.room.name, m.room.canonical_alias, and m.room.member events is likely to indicate a problem with creating the room or synchronising the state table; however clients should still handle this situation. A display name such as "Empty room" (or a localised variant thereof) should be used in this situation.
Clients SHOULD NOT use m.room.aliases events as a source for room names, as it is difficult for clients to agree on the best alias to use, and aliases can change unexpectedly.
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. As a result, this means that clients MUST only send call events to rooms with exactly two participants as currently the WebRTC standard is based around two-party communication.
Message Event
This event is sent by the caller when they wish to establish a call.
Content Key | Type | Description |
---|---|---|
call_id | string | A unique identifer for the call. |
lifetime | integer | The time in milliseconds that the invite is valid for. Once the invite age exceeds this value, clients should discard it. They should also no longer show the call as awaiting an answer in the UI. |
offer | Offer | The session description object |
version | integer | The version of the VoIP specification this message adheres to. This specification is version 0. |
Offer
Offer Key | Type | Description |
---|---|---|
sdp | string | The SDP text of the session description. |
type | string | The type of session description. Must be 'offer'. |
Example:
{ "age": 242352, "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": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.call.invite" }
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 | The ID of the call this event relates to. |
candidates | [Candidate] | Array of objects describing the candidates. |
version | integer | The version of the VoIP specification this messages adheres to. This specification is version 0. |
Candidate
Candidate Key | Type | Description |
---|---|---|
candidate | string | The SDP 'a' line of the candidate. |
sdpMLineIndex | number | The index of the SDP 'm' line this candidate is intended for. |
sdpMid | string | The SDP media type this candidate is intended for. |
Example:
{ "age": 242352, "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": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.call.candidates" }
Message Event
This event is sent by the callee when they wish to answer the call.
Content Key | Type | Description |
---|---|---|
answer | Answer | The session description object |
call_id | string | The ID of the call this event relates to. |
version | number |
Answer
Answer Key | Type | Description |
---|---|---|
sdp | string | The SDP text of the session description. |
type | string | The type of session description. Must be 'answer'. |
Example:
{ "age": 242352, "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": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.call.answer" }
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 | The ID of the call this event relates to. |
version | integer | The version of the VoIP specification this message adheres to. This specification is version 0. |
Example:
{ "age": 242352, "content": { "call_id": "12345", "version": 0 }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "type": "m.call.hangup" }
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 |
---|---|---|
password | string | The password to use. |
ttl | integer | The time-to-live in seconds |
uris | [string] | A list of TURN URIs |
username | string | The username to use. |
Example request:
GET /_matrix/client/r0/voip/turnServer HTTP/1.1
Response:
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 }
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.
Typing Event
Informs the client of the list of users currently typing.
Content Key | Type | Description |
---|---|---|
user_ids | [string] | The list of user IDs typing in this room, if any. |
Example:
{ "content": { "user_ids": [ "@alice:matrix.org", "@bob:example.com" ] }, "room_id": "!z0mnsuiwhifuhwwfw:matrix.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 | ||
timeout | integer | The length of time in milliseconds to mark this user as typing. |
typing | boolean | Required. Whether the user is typing or not. If false, the timeout key can be omitted. |
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 }
Response:
Status code 200:
The new typing state was set.
Example
{}
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.
Each user_id, receipt_type pair must be associated with only a single event_id.
Receipt Event
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
Receipts Key | Type | Description |
---|---|---|
m.read | Users | A collection of users who have sent m.read receipts for this event. |
Users
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
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": "!KpjVgQyZpzBwvMBsnT:matrix.org", "type": "m.receipt" }
In /initialSync, receipts are listed in a separate top level receipts key. In /sync, receipts are contained in the ephemeral block for a 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".
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 {}
Response:
Status code 200:
The receipt was sent.
Example
{}
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.
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. This is one of the few events which are sent outside the context of a room. Presence events are sent to all users who subscribe to this user's presence through a presence list or by sharing membership of a room.
A presence list is a list of user IDs whose presence the user wants to follow. To be added to this list, the user being added must be invited by the list owner who must accept the invitation.
User's presence state is represented by the presence key, which is an enum of one of the following:
Presence Event
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 | The presence state for this user. One of: ["online", "offline", "unavailable", "free_for_chat", "hidden"] |
user_id | string | The user's ID. |
Example:
{ "content": { "avatar_url": "mxc://localhost:wefuiwegh8742w", "last_active_ago": 2478593, "presence": "online", "user_id": "@example:localhost" }, "event_id": "$WLGTSEFSEF:localhost", "type": "m.presence" }
Clients can manually set/get their presence/presence list 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 | ||
status_msg | string | The status message to attach to this state. |
presence | string | Required. The new presence 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." }
Response:
Status code 200:
The new presence state was set.
Example
{}
Get the given user's presence state.
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose presence state to get. |
Response format:
Parameter | Type | Description |
---|---|---|
last_active_ago | integer | The length of time in milliseconds since an action was performed by this user. |
presence | enum | This user's presence. One of: ["online", "offline", "unavailable", "free_for_chat"] |
status_msg | string or null | The state message for this user if one was set. |
Example request:
GET /_matrix/client/r0/presence/%40alice%3Aexample.com/status HTTP/1.1
Response:
Status code 200:
The presence state for this user.
Example
{ "presence": "unavailable", "last_active_ago": 420845 }
Adds or removes users from this presence list.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose presence list is being modified. |
JSON body parameters | ||
drop | array[string] | A list of user IDs to remove from the list. |
invite | array[string] | A list of user IDs to add to the list. |
Example request:
POST /_matrix/client/r0/presence/list/%40alice%3Aexample.com HTTP/1.1 Content-Type: application/json { "invite": [ "@bob:matrix.org" ], "drop": [ "@alice:matrix.org" ] }
Response:
Status code 200:
The list was updated.
Example
{}
Retrieve a list of presence events for every user on this list.
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user whose presence list should be retrieved. |
Response format:
Parameter | Type | Description |
---|---|---|
N/A | [PresenceEvent] |
Example request:
GET /_matrix/client/r0/presence/list/%40alice%3Aexample.com HTTP/1.1
Response:
Status code 200:
A list of presence events for this list.
Example
[ { "content": { "avatar_url": "mxc://matrix.org/AfwefuigfWEfhuiPP", "displayname": "Alice Margatroid", "last_active_ago": 395, "presence": "offline", "user_id": "@alice:matrix.org" }, "type": "m.presence" }, { "content": { "avatar_url": "mxc://matrix.org/FWEhuiwegfWEfhuiwf", "displayname": "Marisa Kirisame", "last_active_ago": 16874, "presence": "online", "user_id": "@marisa:matrix.org" }, "type": "m.presence" } ]
Clients SHOULD implement an "idle timeout". This is a timer which fires after a period of inactivity on the client. The definition of inactivity varies depending on the client. For example, web implementations may determine inactivity to be not moving the mouse for a certain period of time. When this timer fires it should set the presence state to unavailable. When the user becomes active again (e.g. by moving the mouse) the client should set the presence state to online. A timeout value between 1 and 5 minutes is recommended.
Each user's homeserver stores a "presence list" per user. Once a user accepts a presence list, both user's HSes must track the subscription.
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 SHOULD cause an automatic propagation event to occur, informing likely-interested parties of the new values. One of these change mechanisms SHOULD be via m.presence events. These events should set displayname and avatar_url to the new values along with the presence-specific keys. This SHOULD be done automatically by the homeserver when a user successfully changes their display name or avatar URL.
Rationale
The intention for sending this information in m.presence is so that any "user list" can display the current name/presence for a user ID outside the scope of a room e.g. for a user page. This is bundled into a single event for several reasons. The user's display name can change per room. This event provides the "canonical" name for the user. In addition, the name is bundled into a single event for the ease of client implementations. If this was not done, the client would need to search all rooms for their own membership event to pull out the display name.
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 a higher level of availability. Levels of availability are defined from low to high as follows:
Based on this list, changing state from unavailable to online counts as a pro-active event, whereas online to unavailable does not. This timestamp is presented via a key called last_active_ago which gives the relative number of milliseconds since the pro-active event.
Presence information is shared with all users who share a room with the target user. In large public rooms this could be undesirable.
This module allows users to upload content to their homeserver which is retrievable from other homeservers. Its' purpose is to allow users to share attachments in a room. 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.
Uploads are POSTed to a resource on the user's local homeserver which returns a token which is 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).
Clients can upload and download content using the following HTTP APIs.
Download content from the content repository.
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) |
Response format:
Parameter | Type | Description |
---|---|---|
<file> | file | The content that was previously uploaded. |
Content-Type | Header<string> | The content type of the file that was previously uploaded. |
Content-Disposition | Header<string> | The name of the file that was previously uploaded, if set. |
Example request:
GET /_matrix/media/r0/download/matrix.org/ascERGshawAWawugaAcauga HTTP/1.1
Download a thumbnail of the content from the content repository.
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 | The desired width of the thumbnail. The actual thumbnail may not match the size specified. |
height | integer | The desired height of the thumbnail. The actual thumbnail may not match the size specified. |
method | enum | The desired resizing method. One of: ["crop", "scale"] |
Response format:
Parameter | Type | Description |
---|---|---|
<file> | file | A thumbnail of the requested content. |
Content-Type | Header<string> | The content type of the thumbnail. |
Example request:
GET /_matrix/media/r0/thumbnail/matrix.org/ascERGshawAWawugaAcauga?width=64&height=64&method=scale HTTP/1.1
Upload some content to the content repository.
Request format:
Parameter | Type | Description |
---|---|---|
body parameters | ||
<content> | byte | Required. The content to be uploaded. |
header parameters | ||
Content-Type | string | The content type of the file being uploaded |
Response format:
Parameter | Type | Description |
---|---|---|
content_uri | string | The MXC URI to the uploaded content. |
Example request:
POST /_matrix/media/r0/upload HTTP/1.1 Content-Type: application/json <bytes>
Response:
Status code 200:
The MXC URI for the uploaded content.
Example
{ "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" }
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.
Homeservers may generate thumbnails for content uploaded to remote homeservers themselves or may rely on the remote homeserver to thumbnail the content. Homeservers may return thumbnails of a different size to that requested. However homeservers should provide exact matches where reasonable. Homeservers must never upscale images.
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:
End to end encryption is being worked on and will be coming soon.
You can read about what's underway at http://matrix.org/speculator/spec/drafts%2Fe2e/client_server.html#end-to-end-encryption.
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 seen 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 | Who can see the room history. One of: ["invited", "joined", "shared", "world_readable"] |
Example:
{ "age": 242352, "content": { "history_visibility": "shared" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.history_visibility" }
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 solely on the state of the room at that event:
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.
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 | ||
lang | string | Required. The preferred language for receiving notifications (e.g. 'en' or 'en-US') |
kind | string | Required. The kind of pusher to configure. "http" makes a pusher that sends HTTP pokes. null deletes the pusher. |
data | object | 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. |
data.url | string | Required if kind is http. The URL to use to send notifications to. |
device_display_name | string | Required. A string that will allow the user to identify what device owns this pusher. |
app_id | string | Required. This is a reverse-DNS style identifier for the application. It is recommended that this end with the platform, such that different platform versions get different app identifiers. Max length, 64 chars. |
profile_tag | string | Required. This is a string that determines what set of device rules will be matched when evaluating push rules for this pusher. It is an arbitrary string. Multiple devices may use the same profile_tag. It is advised that when an app's data is copied or restored to a different device, this value remain the same. Client apps should offer ways to change the profile_tag, optionally copying rules from the old profile tag. Max length, 32 bytes. |
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. |
app_display_name | string | Required. A string that will allow the user to identify what application owns this pusher. |
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. |
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", "app_id": "com.example.app.ios", "profile_tag": "4bea66906d0111e59d70feff819cdc9f", "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ", "data": { "url": "https://push-gateway.location.here" }, "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" }
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:
Push rules may be either global or device-specific. Device specific rules only affect delivery of notifications via pushers with a matching profile_tag. All device-specific rules have a higher priority than global rules. 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 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" "pattern": "[the local part of the user's Matrix ID]", "actions": [ "notify", { "set_tweak": "sound", "value": "default" } ], }
Matches any message whose content is unencrypted and contains the user's current display name in the room in which it was sent.
Definition (this rule can only be an override or underride rule):
{ "rule_id": ".m.rule.contains_display_name" "conditions": [ { "kind": "contains_display_name" } ], "actions": [ "notify", { "set_tweak": "sound", "value": "default" } ], }
Matches any message sent in a room with exactly two members.
Definition (this rule can only be an override or underride rule):
{ "rule_id": ".m.rule.room_two_members" "conditions": [ { "is": "2", "kind": "room_member_count" } ], "actions": [ "notify", { "set_tweak": "sound", "value": "default" } ], }
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', 'conditions': [ { 'kind': 'event_match', 'key': 'content.msgtype', 'pattern': 'm.notice', } ], 'actions': [ 'dont-notify', ] }
Matches any message. Used to define the behaviour of messages that match no other rules. If homeservers define this it should be the lowest priority underride rule.
Definition:
{ "rule_id": ".m.rule.fallback" "conditions": [], "actions": [ "notify" ], }
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:
Matches the profile_tag of the device that the notification would be delivered to. Parameters:
This matches the current number of members in the room. Parameters:
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.
Requires auth: | Yes. |
---|
Request format:
No parameters
Response format:
Parameter | Type | Description |
---|---|---|
device | {$PROFILE_TAG: Ruleset} | A dictionary of profile tags to rulesets. |
global | Ruleset | The global ruleset. |
Ruleset
Parameter | Type | Description |
---|---|---|
content | [PushRule] | |
override | [PushRule] | |
room | [PushRule] | |
sender | [PushRule] | |
underride | [PushRule] |
PushRule
Parameter | Type | Description |
---|---|---|
actions | [object or string] | |
default | boolean | |
enabled | boolean | |
rule_id | string |
Example request:
GET /_matrix/client/r0/pushrules/ HTTP/1.1
Response:
Status code 200:
All the push rulesets for this user.
Example
{ "device": {}, "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" } ] } }
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 |
---|---|---|
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. |
JSON body parameters | ||
conditions | array[object] | 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. |
conditions[0].kind | enum | One of: ["event_match", "profile_tag", "contains_display_name", "room_member_count"] |
actions | array[string] | Required. The action(s) to perform when the conditions for this rule are met. |
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 rule. |
after | string | This makes the new rule the next-less important rule relative to the given rule. |
Example request:
PUT /_matrix/client/r0/pushrules/global/room/%23spam%3Aexample.com?before=someRuleId&after=anotherRuleId HTTP/1.1 Content-Type: application/json { "pattern": "cake*lie", "actions": ["notify"] }
Responses:
Status code 200:
The pusher was set.
Example
{}
Status code 400:
There was a problem configuring this push rule.
Example
{ "error": "before/after rule not found: someRuleId", "errcode": "M_UNKNOWN" }
This endpoint removes the push rule defined in the path.
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. |
Example request:
DELETE /_matrix/client/r0/pushrules/global/room/%23spam%3Aexample.com HTTP/1.1
Response:
Status code 200:
The push rule was deleted.
Example
{}
Retrieve a single specified push rule.
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. |
Example request:
GET /_matrix/client/r0/pushrules/global/room/%23spam%3Aexample.com 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" ], "rule_id": "#spam:matrix.org", "enabled": true }
This endpoint allows clients to enable or disable the specified push rule.
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. |
JSON body parameters | ||
enabled | boolean | Required. Whether the push rule is enabled or not. |
Example request:
PUT /_matrix/client/r0/pushrules/global/room/%23spam%3Aexample.com/enabled HTTP/1.1 Content-Type: application/json { "enabled": true }
Response:
Status code 200:
The push rule was enabled or disabled.
Example
{}
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/api/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/api/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/api/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/api/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/api/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.
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 | 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 | 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 | A base64-encoded ed25519 key with which token must be signed. |
Example:
{ "age": 242352, "content": { "display_name": "Alice Margatroid", "key_validity_url": "https://magic.forest/verifykey", "public_key": "abc123" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts": 1431961217939, "room_id": "!Cuyf34gef24t:localhost", "sender": "@example:localhost", "state_key": "pc98", "type": "m.room.third_party_invite" }
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"}
All homeservers MUST verify the signature in the event's content.third_party_invite.signed object.
When a homeserver inserts an m.room.member invite event into the graph because of an m.room.third_party_invite event, that homesever MUST validate that the public key used for signing is still valid, by checking key_validity_url from the m.room.third_party_invite. It does this by making an HTTP GET request to key_validity_url:
Schema:
=> GET $key_validity_url?public_key=$public_key <= HTTP/1.1 200 OK { "valid": true|false }
Example:
key_validity_url = https://identity.server/is_valid public_key = ALJWLAFQfqffQHFqFfeqFUOEHf4AIHfefh4 => GET https://identity.server/is_valid?public_key=ALJWLAFQfqffQHFqFfeqFUOEHf4AIHfefh4 <= HTTP/1.1 200 OK { "valid": true }
with the querystring ?public_key=``public_key``. A JSON object will be returned. The invitation is valid if the object contains a key named valid which is true. Otherwise, the invitation MUST be rejected. This request is idempotent and may be retried by the homeserver.
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:
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 privary 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.
Performs a full text search across different categories.
Rate-limited: | Yes. |
---|---|
Requires auth: | Yes. |
Request format:
Parameter | Type | Description |
---|---|---|
JSON body parameters | ||
search_categories | object | Required. Describes which categories to search in and their criteria. |
search_categories.room_events | Room Events | Mapping of category name to search criteria. |
search_categories.room_events.event_context | Event Context | Configures whether any context for the events returned are included in the response. |
search_categories.room_events.filter | Filter | This takes a filter. |
search_categories.room_events.groupings | Groupings | Requests that the server partitions the result set based on the provided list of keys. |
search_categories.room_events.include_state | boolean | Requests the server return the current state for each room returned. |
search_categories.room_events.keys | [enum] | The keys to search. Defaults to all. One of: ["content.body", "content.name", "content.topic"] |
search_categories.room_events.order_by | enum | The order in which to search for results. One of: ["recent", "rank"] |
search_categories.room_events.search_term | string | Required. The string to search events for |
search_categories.room_events.event_context.after_limit | integer | How many events after the result are returned. |
search_categories.room_events.event_context.before_limit | integer | How many events before the result are returned. |
search_categories.room_events.event_context.include_profile | boolean | Requests that the server returns the historic profile information for the users that sent the events that were returned. |
search_categories.room_events.groupings.group_by | [Group] | List of groups to request. |
search_categories.room_events.groupings.group_by.key | enum | Key that defines the group. One of: ["room_id", "sender"] |
Response format:
Results
Parameter | Type | Description |
---|---|---|
search_categories | Categories | Describes which categories to search in and their criteria. |
Categories
Parameter | Type | Description |
---|---|---|
room_events | Room Event Results | Mapping of category name to search criteria. |
Room Event Results
Parameter | Type | Description |
---|---|---|
count | number | Total number of results found |
groups | {string: {string: Group Value}} | Any groups that were requested. |
next_batch | string | Token that can be used to get the next batch of results, if exists. |
results | [Result] | List of results in the requested order. |
state | {string: array} | 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. |
Group Value
Parameter | Type | Description |
---|---|---|
next_batch | string | Token that can be used to get the next batch of results in the group, if exists. |
order | integer | Key that can be used to order different groups. |
results | [string] | Which results are in this group. |
Result
Parameter | Type | Description |
---|---|---|
context | Event Context | Context for result, if requested. |
rank | number | A number that describes how closely this result matches the search. Higher is closer. |
result | Event | The event that matched. |
Event Context
Parameter | Type | Description |
---|---|---|
end | string | Pagination token for the end of the chunk |
events_after | [Event] | Events just after the result. |
events_before | [Event] | Events just before the result. |
profile_info | {string: User Profile} | The historic profile information of the users that sent the events returned. |
start | string | Pagination token for the start of the chunk |
User Profile
Parameter | Type | Description |
---|---|---|
avatar_url | string | |
displayname | string |
Event
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
UnsignedData
Parameter | Type | Description |
---|---|---|
age | integer | The time in milliseconds that has elapsed since the event was sent |
redacted_because | string | The reason this event was redacted, if it was redacted |
transaction_id | string | The client-supplied transaction ID, if the client being given the event is the same one which sent it. |
Example request:
POST /_matrix/client/r0/search 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" } ] } }
Response:
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" ] } } }, "next_batch": "5FdgFsd234dfgsdfFD", "count": 24, "results": [ { "rank": 0.00424866, "result": { "age": 526228296, "content": { "body": "Test content martians and men", "msgtype": "m.text" }, "event_id": "$144429830826TWwbB:localhost", "origin_server_ts": 1444298308034, "room_id": "!qPewotXpIctQySfjSy:localhost", "type": "m.room.message", "sender": "@test:localhost" } } ] } } }
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 may not match the number of results. For example due to the search query matching 1000s of results and the server truncating the response.
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 which 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.
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 | Whether guests can join the room. One of: ["can_join", "forbidden"] |
Example:
{ "age": 242353, "content": { "guest_access": "can_join" }, "event_id": "$WLGTSEFSEG:localhost", "origin_server_ts": 1431961217938, "room_id": "!Cuyf34gef24u:localhost", "sender": "@example:localhost", "state_key": "", "type": "m.room.guest_access" }
The following API endpoints are allowed to be accessed by guest accounts for retrieving events:
There is also a special version of the GET /events endpoint:
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 non-guest /events endpoint, but can be called by guest users.
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 | array | The room IDs for which events should be returned. |
Response format:
Parameter | Type | Description |
---|---|---|
chunk | [Event] | An array of events. |
end | string | A token which correlates to the last value in chunk. This token should be used in the next request to /events. |
start | string | A token which correlates to the first value in chunk. This is usually the same token supplied to from=. |
Event
Parameter | Type | Description |
---|---|---|
content | EventContent | The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body. |
event_id | string | Required. The globally unique event identifier. |
room_id | string | Required. The ID of the room associated with this event. |
sender | string | Required. Contains the fully-qualified ID of the user who sent this event. |
type | string | The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type' |
unsigned | UnsignedData | Contains optional extra information about the event. |
UnsignedData
Parameter | Type | Description |
---|---|---|
age | integer | The time in milliseconds that has elapsed since the event was sent |
redacted_because | string | The reason this event was redacted, if it was redacted |
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&room_id=%21the%3Arainbow HTTP/1.1
Response:
Status code 200:
The events received, which may be none.
Example
{ "start": "s3456_9_0", "end": "s3457_9_0", "chunk": [ { "age": 32, "content": { "body": "incoming message", "msgtype": "m.text" }, "event_id": "$14328055551tzaee:localhost", "origin_server_ts": 1432804485886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "sender": "@bob:localhost" } ] }
They will only return events which happened while the room state had the m.room.history_visibility state event present with history_visibility value world_readable. Guest clients do not need to join rooms in order to receive events for them.
The following API endpoints are allowed to be accessed by guest accounts for sending events:
Guest clients do need to join rooms in order to send events to them.
The following API endpoints are allowed to be accessed by guest accounts for their own account maintenance:
Servers are required to only return events to guest accounts for rooms where the room state at the event had the m.room.history_visibility state event present with history_visibility value world_readable. These events may be returned even if the anonymous user is not joined to the room.
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.
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 guest users.
Homeservers may want to enable protections such as captchas for guest registration to prevent spam, denial of service, and similar attacks.
Users can add tags to rooms. Tags are short strings used to label rooms, e.g. "work", "family". 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 in a /sync.
The m.tag can also be received in a /events response or in the account_data section of a room in /initialSync. m.tag events appearing in /events will have a room_id with the room the tags are for.
Each tag has an associated JSON object with 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 string. The string are compared lexicographically by unicode codepoint to determine which should displayed first. So a room with a tag with an order key of "apples" would appear before a room with a tag with an order key of "oranges". 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 name of a tag should be human readable. When displaying tags for a room a client should display this human readable name. When adding a tag for a room a client may offer a list to choose from that includes all the tags that the user has previously set on any of their rooms.
Two special names are listed in the specification:
Tag Event
Informs the client of tags on a room.
Content Key | Type | Description |
---|---|---|
tags | {string: Tag} | The tags on the room and their contents. |
Example:
{ "content": { "tags": { "work": { "order": 1 } } }, "type": "m.tag" }
List the tags set by a user on a room.
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 | Tags |
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": { "work": {"order": "1"}, "pinned": {} } }
Add a tag to the room.
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. |
Example request:
PUT /_matrix/client/r0/user/%40alice%3Aexample.com/rooms/%21726s6s6q%3Aexample.com/tags/work HTTP/1.1 Content-Type: application/json {"order": "1"}
Response:
Status code 200:
The tag was successfully added.
Example
{}
Remove a tag from the room.
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/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 recieves 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 /initialSync. 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.
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"}
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.
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"}
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.
Requires auth: | Yes. |
---|
Request format:
Parameter | Type | Description |
---|---|---|
path parameters | ||
userId | string | Required. The user to look up. |
Response format:
Parameter | Type | Description |
---|---|---|
devices | {string: DeviceInfo} | Each key is an identitfier for one of the user's devices. |
user_id | string | The Matrix user ID of the user. |
DeviceInfo
Parameter | Type | Description |
---|---|---|
sessions | [SessionInfo] | A user's sessions (i.e. what they did with an access token from one login). |
SessionInfo
Parameter | Type | Description |
---|---|---|
connections | [ConnectionInfo] | Information particular connections in the session. |
ConnectionInfo
Parameter | Type | Description |
---|---|---|
ip | string | Most recently seen IP address of the session. |
last_seen | number | 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.
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.
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 |
---|---|---|
end | string | A token that can be used to paginate forwards with. |
events_after | [RoomEvent] | A list of room events that happened just after the requested event. |
events_before | [RoomEvent] | A list of room events that happened just before the requested event. |
start | string | A token that can be used to paginate backwards with. |
state | [RoomEvent] | The state of the room at the last event returned. |
Example request:
GET /_matrix/client/api/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": [ { "age": 91911336, "content": { "body": "7", "msgtype": "m.text" }, "event_id": "$14460306086CiUaL:localhost:8480", "origin_server_ts": 1446030608551, "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", "type": "m.room.message", "user_id": "@test:localhost:8480" } ], "events_before": [ { "age": 91911903, "content": { "body": "5", "msgtype": "m.text" }, "event_id": "$14460306074UYTlh:localhost:8480", "origin_server_ts": 1446030607984, "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", "type": "m.room.message", "user_id": "@test:localhost:8480" } ], "start": "t27-54_2_0_2", "state": [ { "age": 3123715284, "content": { "creator": "@test:localhost:8480" }, "event_id": "$14429988040dgQAE:localhost:8480", "origin_server_ts": 1442998804603, "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", "state_key": "", "type": "m.room.create", "user_id": "@test:localhost:8480" }, { "age": 2067105053, "content": { "avatar_url": "mxc://localhost:8480/tVWZTAIIfqtXMZZtmGCkVjTD#auto", "displayname": "Bob2", "membership": "join" }, "event_id": "$14440554144URDbf:localhost:8480", "origin_server_ts": 1444055414834, "replaces_state": "$14440552472PgiGk:localhost:8480", "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", "state_key": "@test:localhost:8480", "type": "m.room.member", "user_id": "@test:localhost:8480" } ] }
The server must only return results that the user has permission to see.