This specification has been generated from https://github.com/matrix-org/matrix-doc using https://github.com/matrix-org/matrix-doc/blob/master/scripts/gendoc.py as of revision master,24356d8 - https://github.com/matrix-org/matrix-doc/tree/24356d8
This update fundamentally restructures the specification. The specification has been split into more digestible "modules" which each describe a particular function (e.g. typing). This was done in order make the specification easier to maintain and help define which modules are mandatory for certain types of clients. Types of clients along with the mandatory modules can be found in a new "Feature Profiles" section. This update also begins to aggressively standardise on using Swagger and JSON Schema to document HTTP endpoints and Events respectively. It also introduces a number of new concepts to Matrix.
For a full changelog, see https://github.com/matrix-org/matrix-doc/blob/master/CHANGELOG.rst
Table of Contents
Warning
The Matrix specification is still evolving: the APIs are not yet frozen and this document is in places a work in progress or stale. We have made every effort to clearly flag areas which are still being finalised. We're publishing it at this point because it's complete enough to be more than useful and provide a canonical reference to how Matrix is evolving. Our end goal is to mirror WHATWG's Living Standard.
Matrix is a set of open APIs for open-federated Instant Messaging (IM), Voice over IP (VoIP) and Internet of Things (IoT) communication, designed to create and support a new global real-time communication ecosystem. The intention is to provide an open decentralised pubsub layer for the internet for securely persisting and publishing/subscribing JSON objects. This specification is the ongoing result of standardising the APIs used by the various components of the Matrix ecosystem to communicate with one another.
The principles that Matrix attempts to follow are:
The functionality that Matrix provides includes:
The end goal of Matrix is to be a ubiquitous messaging layer for synchronising arbitrary data between sets of people, devices and services - be that for instant messages, VoIP call setups, or any other objects that need to be reliably and persistently pushed from A to B in an inter-operable and federated manner.
Matrix defines APIs for synchronising extensible JSON objects known as "events" between compatible clients, servers and services. Clients are typically messaging/VoIP applications or IoT devices/hubs and communicate by synchronising communication history with their "homeserver" using the "Client-Server API". Each homeserver stores the communication history and account information for all of its clients, and shares data with the wider Matrix ecosystem by synchronising communication history with other homeservers and their clients.
Clients typically communicate with each other by emitting events in the context of a virtual "room". Room data is replicated across all of the homeservers whose users are participating in a given room. As such, no single homeserver has control or ownership over a given room. Homeservers model communication history as a partially ordered graph of events known as the room's "event graph", which is synchronised with eventual consistency between the participating servers using the "Server-Server API". This process of synchronising shared conversation history between homeservers run by different parties is called "Federation". Matrix optimises for the the Availability and Partitioned properties of CAP theorem at the expense of Consistency.
For example, for client A to send a message to client B, client A performs an HTTP PUT of the required JSON event on its homeserver (HS) using the client-server API. A's HS appends this event to its copy of the room's event graph, signing the message in the context of the graph for integrity. A's HS then replicates the message to B's HS by performing an HTTP PUT using the server-server API. B's HS authenticates the request, validates the event's signature, authorises the event's contents and then adds it to its copy of the room's event graph. Client B then receives the message from his homeserver via a long-lived GET request.
How data flows between clients ============================== { Matrix client A } { Matrix client B } ^ | ^ | | events | Client-Server API | events | | V | V +------------------+ +------------------+ | |---------( HTTPS )--------->| | | Home Server | | Home Server | | |<--------( HTTPS )----------| | +------------------+ Server-Server API +------------------+ History Synchronisation (Federation)
Each client is associated with a user account, which is identified in Matrix using a unique "User ID". This ID is namespaced to the homeserver which allocated the account and has the form:
@localpart:domain
The localpart of a user ID may be a user name, or an opaque ID identifying this user. The domain of a user ID is the domain of the homeserver.
All data exchanged over Matrix is expressed as an "event". Typically each client action (e.g. sending a message) correlates with exactly one event. Each event has a type which is used to differentiate different kinds of data. type values MUST be uniquely globally namespaced following Java's package naming conventions, e.g. com.example.myapp.event. The special top-level namespace m. is reserved for events defined in the Matrix specification - for instance m.room.message is the event type for instant messages. Events are usually sent in the context of a "Room".
Events exchanged in the context of a room are stored in a directed acyclic graph (DAG) called an "event graph". The partial ordering of this graph gives the chronological ordering of events within the room. Each event in the graph has a list of zero or more "parent" events, which refer to any preceding events which have no chronological successor from the perspective of the homeserver which created the event.
Typically an event has a single parent: the most recent message in the room at the point it was sent. However, homeservers may legitimately race with each other when sending messages, resulting in a single event having multiple successors. The next event added to the graph thus will have multiple parents. Every event graph has a single root event with no parent.
To order and ease chronological comparison between the events within the graph, homeservers maintain a depth metadata field on each event. An event's depth is a positive integer that is strictly greater than the depths of any of its parents. The root event should have a depth of 1. Thus if one event is before another, then it must have a strictly smaller depth.
A room is a conceptual place where users can send and receive events. Events are sent to a room, and all participants in that room with sufficient access will receive the event. Rooms are uniquely identified internally via "Room IDs", which have the form:
!opaque_id:domain
There is exactly one room ID for each room. Whilst the room ID does contain a domain, it is simply for globally namespacing room IDs. The room does NOT reside on the domain specified. Room IDs are not meant to be human readable. They are case-sensitive. The following conceptual diagram shows an m.room.message event being sent to the room !qporfwt:matrix.org:
{ @alice:matrix.org } { @bob:domain.com } | ^ | | [HTTP POST] [HTTP GET] Room ID: !qporfwt:matrix.org Room ID: !qporfwt:matrix.org Event type: m.room.message Event type: m.room.message Content: { JSON object } Content: { JSON object } | | V | +------------------+ +------------------+ | Home Server | | Home Server | | matrix.org | | domain.com | +------------------+ +------------------+ | ^ | [HTTP PUT] | | Room ID: !qporfwt:matrix.org | | Event type: m.room.message | | Content: { JSON object } | `-------> Pointer to the preceding message ------` PKI signature from matrix.org Transaction-layer metadata PKI Authorization header ................................... | Shared Data | | State: | | Room ID: !qporfwt:matrix.org | | Servers: matrix.org, domain.com | | Members: | | - @alice:matrix.org | | - @bob:domain.com | | Messages: | | - @alice:matrix.org | | Content: { JSON object } | |...................................|
Federation maintains shared data structures per-room between multiple home servers. The data is split into message events and state events.
The state of the room at a given point is calculated by considering all events preceding and including a given event in the graph. Where events describe the same state, a merge conflict algorithm is applied. The state resolution algorithm is transitive and does not depend on server state, as it must consistently select the same event irrespective of the server or the order the events were received in. Events are signed by the originating server (the signature includes the parent relations, type, depth and payload hash) and are pushed over federation to the participating servers in a room, currently using full mesh topology. Servers may also request backfill of events over federation from the other servers participating in a room.
Each room can also have multiple "Room Aliases", which look like:
#room_alias:domain
A room alias "points" to a room ID and is the human-readable label by which rooms are publicised and discovered. The room ID the alias is pointing to can be obtained by visiting the domain specified. Note that the mapping from a room alias to a room ID is not fixed, and may change over time to point to a different room ID. For this reason, Clients SHOULD resolve the room alias to a room ID once and then use that ID on subsequent requests. Room aliases MUST NOT exceed 255 bytes (including the domain).
When resolving a room alias the server will also respond with a list of servers that are in the room that can be used to join via.
HTTP GET #matrix:domain.com !aaabaa:matrix.org | ^ | | _______V____________________|____ | domain.com | | Mappings: | | #matrix >> !aaabaa:matrix.org | | #golf >> !wfeiofh:sport.com | | #bike >> !4rguxf:matrix.org | |________________________________|
Users in Matrix are identified via their matrix user ID (MXID). However, existing 3rd party ID namespaces can also be used in order to identify Matrix users. A Matrix "Identity" describes both the user ID and any other existing IDs from third party namespaces linked to their account. Matrix users can link third-party IDs (3PIDs) such as email addresses, social network accounts and phone numbers to their user ID. Linking 3PIDs creates a mapping from a 3PID to a user ID. This mapping can then be used by Matrix users in order to discover the MXIDs of their contacts. In order to ensure that the mapping from 3PID to user ID is genuine, a globally federated cluster of trusted "Identity Servers" (IS) are used to verify the 3PID and persist and replicate the mappings.
Usage of an IS is not required in order for a client application to be part of the Matrix ecosystem. However, without one clients will not be able to look up user IDs using 3PIDs.
Users may publish arbitrary key/value data associated with their account - such as a human readable display name, a profile photo URL, contact information (email address, phone numbers, website URLs etc).
Users may also store arbitrary private key/value data in their account - such as client preferences, or server configuration settings which lack any other dedicated API. The API is symmetrical to managing Profile data.
The mandatory baseline for communication in Matrix is exchanging JSON objects over HTTP APIs. HTTPS is mandated as the baseline for server-server (federation) communication. HTTPS is recommended for client-server communication, although HTTP may be supported as a fallback to support basic HTTP clients. More efficient optional transports for client-server communication 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 POST to submit requests. This means these requests are not idempotent. The C-S API also allows HTTP PUT to make requests idempotent. In order to use a PUT, paths should be suffixed with /{txnId}. {txnId} is a unique client-generated transaction ID which identifies the request, and is scoped to a given Client (identified by that client's access_token). Crucially, 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). It is preferable to use HTTP PUT to make sure requests to send messages do not get sent more than once should clients need to retransmit requests.
Valid requests look like:
POST /some/path/here?access_token=secret { "key": "This is a post." } PUT /some/path/here/11?access_token=secret { "key": "This is a put with a txnId of 11." }
In contrast, these are invalid requests:
POST /some/path/here/11?access_token=secret { "key": "This is a post, but it has a txnId." } PUT /some/path/here?access_token=secret { "key": "This is a put but it is missing a txnId." }
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.
This mostly describes v1 of the Client-Server API as featured in the original September 2014 launch of Matrix, apart from user-interactive authentication where it is encouraged to move to v2, therefore this is the version documented here. Version 2 is currently in development (as of Jan-March 2015) as an incremental but backwards-incompatible refinement of Version 1 and will be released shortly.
Documentation for the old V1 authentication is still available separately.
Most API endpoints require the user to identify themselves by presenting previously obtained credentials in the form of an access_token query parameter.
In API version 2, when credentials are 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.
This section refers to API Version 2.
Some API endpoints such as login or register require authentication that interacts with the user. The home server 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 home servers should authorise their users but instead defines the standard interface which implementations should follow so that ANY client can login to ANY home server.
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. Home Servers may allow requests that don't require auth by offering a stage with only the m.login.dummy auth type. The home server 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 home server, 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 home server 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 home server 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 home server 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 home server 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 home server 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. Home servers 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 home server.
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 the Home Server base URL plus prefix, plus:
/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 home server.
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.
This section refers to API Version 2. These API calls currently use the prefix /_matrix/client/v2_alpha.
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 Home Server 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/api/v2_alpha/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.
Home Servers 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." }
Old V1 API docs: /register
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 Home Server 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/api/v1/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/api/v1/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 $V2PREFIX/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 Home Server 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 Home Server could not find a matching account in its database.
Request:
POST $V2PREFIX/account/3pid
Used to add contact information to the user's account.
The body of the POST request is a JSON object containing:
The contact information object comprises:
On success, the empty JSON object is returned.
May also return error codes:
Request:
GET $V2PREFIX/account/3pid
This returns a list of third party identifiers that the Home Server 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 Home Server as, for example, identifiers that it will accept to reset the user's account password.
Returns a JSON object with the key threepids whose contents is an array of objects with the following keys:
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".
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 POSTing message or state events, and can read from the stream via the /initialSync, /rooms/<room_id>/initialSync, Event Stream and /rooms/<room_id>/messages APIs.
For reading events, the intended flow of operation is to call $PREFIX/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, $PREFIX/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 $PREFIX/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 $PREFIX/events and poll again.
Similarly, to paginate events backwards in order to lazy-load in previous history from the room, you simply GET $PREFIX/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 home server 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 home server. 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 |
|---|---|---|
| event_id | string | The globally unique event identifier. |
| room_id | string | The ID of the room associated with this event. |
| user_id | string | Contains the fully-qualified ID of the user who sent this event. |
Example request:
GET /_matrix/client/api/v1/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":<PHONE_NUMBER>886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "user_id": "@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/api/v1/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", "user_id": "@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] |
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' |
RoomInfo
| Parameter | Type | Description |
|---|---|---|
| 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"] |
InviteEvent
| Parameter | Type | Description |
|---|---|---|
| content | {EventContent} | |
| invite_room_state | [StrippedState] | A subset of the state of the room at the time of the invite, if membership is invite |
| state_key | string | The user_id this membership event relates to. |
| type | string | Must be 'm.room.member'. |
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} |
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. |
| 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 |
|---|---|---|
| event_id | string | The globally unique event identifier. |
| room_id | string | The ID of the room associated with this event. |
| user_id | string | Contains the fully-qualified ID of the user who sent this event. |
StateEvent
| Parameter | Type | Description |
|---|---|---|
| prev_content | {EventContent} | 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 '_'. |
Example request:
GET /_matrix/client/api/v1/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" } ], "rooms": [ { "membership": "join", "messages": { "chunk": [ { "age": 343513403, "content": { "body": "foo", "msgtype": "m.text" }, "event_id": "$14328044851tzTJS:localhost", "origin_server_ts":<PHONE_NUMBER>886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "user_id": "@alice:localhost" }, { "age": 343511809, "content": { "body": "bar", "msgtype": "m.text" }, "event_id": "$14328044872spjFg:localhost", "origin_server_ts":<PHONE_NUMBER>480, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", "user_id": "@bob:localhost" } ], "end": "s3456_9_0", "start": "t44-3453_9_0" }, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state": [ { "age":<PHONE_NUMBER>, "content": { "join_rule": "public" }, "event_id": "$14259997323TLwtb:localhost", "origin_server_ts":<PHONE_NUMBER>392, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.join_rules", "user_id": "@alice:localhost" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto", "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:localhost", "membership": "join", "origin_server_ts":<PHONE_NUMBER>277, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "@alice:localhost", "type": "m.room.member", "user_id": "@alice:localhost" }, { "age":<PHONE_NUMBER>, "content": { "creator": "@alice:localhost" }, "event_id": "$14259997320KhbwJ:localhost", "origin_server_ts":<PHONE_NUMBER>089, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.create", "user_id": "@alice:localhost" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:localhost", "origin_server_ts":<PHONE_NUMBER>569, "replaces_state": "$142652023736BSXcM:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "@bob:localhost", "type": "m.room.member", "user_id": "@bob:localhost" }, { "age":<PHONE_NUMBER>, "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":<PHONE_NUMBER>285, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.power_levels", "user_id": "@alice:localhost" } ], "visibility": "private" } ] }
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. |
| 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 | [NO_TITLE] | List of events |
NO_TITLE
| 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. |
| replaces_state | string | Optional. The event_id of the previous event 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. |
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 | [NO_TITLE] | List of events |
Joined Room
| Parameter | Type | Description |
|---|---|---|
| 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. |
Ephemeral
| Parameter | Type | Description |
|---|---|---|
| events | [NO_TITLE] | List of events |
State
| Parameter | Type | Description |
|---|---|---|
| events | [NO_TITLE] | List of events |
Timeline
| Parameter | Type | Description |
|---|---|---|
| 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 |
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. |
Example request:
GET /_matrix/client/v2_alpha/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"} } ] }, "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":<PHONE_NUMBER>795, "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":<PHONE_NUMBER>795, "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":<PHONE_NUMBER>797, "event_id": "$74686972643033:example.com" } ], "limited": true, "prev_batch": "t34-23535_0_0" }, "ephemeral": { "events": [ { "type": "m.typing", "content": {"user_ids": ["@alice:example.com"]} } ] } } }, "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 |
|---|---|---|
| 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"] |
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 |
|---|---|---|
| event_id | string | The globally unique event identifier. |
| room_id | string | The ID of the room associated with this event. |
| user_id | string | Contains the fully-qualified ID of the user who sent this event. |
StateEvent
| Parameter | Type | Description |
|---|---|---|
| prev_content | {EventContent} | 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 '_'. |
Example request:
GET /_matrix/client/api/v1/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":<PHONE_NUMBER>886, "room_id": "!636q39766251:example.com", "type": "m.room.message", "user_id": "@alice:example.com" }, { "age": 343511809, "content": { "body": "bar", "msgtype": "m.text" }, "event_id": "$14328044872spjFg:example.com", "origin_server_ts":<PHONE_NUMBER>480, "room_id": "!636q39766251:example.com", "type": "m.room.message", "user_id": "@bob:example.com" } ], "end": "s3456_9_0", "start": "t44-3453_9_0" }, "room_id": "!636q39766251:example.com", "state": [ { "age":<PHONE_NUMBER>, "content": { "join_rule": "public" }, "event_id": "$14259997323TLwtb:example.com", "origin_server_ts":<PHONE_NUMBER>392, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.join_rules", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", "membership": "join", "origin_server_ts":<PHONE_NUMBER>277, "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "creator": "@alice:example.com" }, "event_id": "$14259997320KhbwJ:example.com", "origin_server_ts":<PHONE_NUMBER>089, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.create", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:example.com", "origin_server_ts":<PHONE_NUMBER>569, "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", "user_id": "@bob:example.com" }, { "age":<PHONE_NUMBER>, "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":<PHONE_NUMBER>285, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.power_levels", "user_id": "@alice:example.com" } ], "visibility": "private" }
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} | |
| invite_room_state | [StrippedState] | A subset of the state of the room at the time of the invite, if membership is invite |
| state_key | string | The user_id this membership event relates to. |
| type | string | Must be 'm.room.member'. |
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} |
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. |
| 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"] |
Example request:
GET /_matrix/client/api/v1/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":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", "membership": "join", "origin_server_ts":<PHONE_NUMBER>277, "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:example.com", "origin_server_ts":<PHONE_NUMBER>569, "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", "user_id": "@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/api/v1/rooms/%21636q39766251%3Aexample.com/state HTTP/1.1
Response:
Status code 200:
The current state of the room
Example
[ { "age":<PHONE_NUMBER>, "content": { "join_rule": "public" }, "event_id": "$14259997323TLwtb:example.com", "origin_server_ts":<PHONE_NUMBER>392, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.join_rules", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", "membership": "join", "origin_server_ts":<PHONE_NUMBER>277, "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "creator": "@alice:example.com" }, "event_id": "$14259997320KhbwJ:example.com", "origin_server_ts":<PHONE_NUMBER>089, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.create", "user_id": "@alice:example.com" }, { "age":<PHONE_NUMBER>, "content": { "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", "displayname": "Bob", "membership": "join" }, "event_id": "$1431525430134MxlLX:example.com", "origin_server_ts":<PHONE_NUMBER>569, "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", "user_id": "@bob:example.com" }, { "age":<PHONE_NUMBER>, "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":<PHONE_NUMBER>285, "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.power_levels", "user_id": "@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.
| Requires auth: | Yes. |
|---|
Request format:
| Parameter | Type | Description |
|---|---|---|
| path parameters | ||
| roomId | string | Required. The room to look up the state in. |
| eventType | string | Required. The type of state to look up. |
| stateKey | string | Required. The key of the state to look up. Defaults to the empty string. |
Example request:
GET /_matrix/client/api/v1/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/api/v1/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":<PHONE_NUMBER>737, "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":<PHONE_NUMBER>656 , "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":<PHONE_NUMBER>990, "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. If the state event has an empty state_key, it can be omitted from the path.
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/api/v1/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 can be used to send a message event to a room; however the lack of a transaction ID means that it is possible to cause message duplication if events are resent on error, so it is preferable to use PUT /_matrix/client/api/v1/rooms/{roomId}/send/{eventType}/{txnId}.
| 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. |
Response format:
| Parameter | Type | Description |
|---|---|---|
| event_id | string | A unique identifier for the event. |
Example request:
POST /_matrix/client/api/v1/rooms/%21636q39766251%3Aexample.com/send/m.room.message 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" }
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/api/v1/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:
m.room.member allows key membership
m.room.create allows key creator
m.room.join_rules allows key join_rule
kick, redact, state_default, users, users_default.
m.room.aliases allows key aliases
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.
The home server 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. |
| 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 home server 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. |
| 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. |
| 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 | |
| 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. |
Response format:
| Parameter | Type | Description |
|---|---|---|
| room_id | string | The created room's ID. |
Example request:
POST /_matrix/client/api/v1/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" }
Note
This section is a work in progress.
Room aliases can be created by sending a PUT /directory/room/<room alias>:
{ "room_id": <room id> }
They can be deleted by sending a DELETE /directory/room/<room alias> with no content. Only some privileged users may be able to delete room aliases, e.g. server admins, the creator of the room alias, etc. This specification does not outline the privilege level required for deleting room aliases.
As room aliases are scoped to a particular home server domain name, it is likely that a home server will reject attempts to maintain aliases on other domain names. This specification does not provide a way for home servers 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.
Room aliases can be checked in the same way they are resolved; by sending a GET /directory/room/<room alias>:
{ "room_id": <room id>, "servers": [ <domain>, <domain2>, <domain3> ] }
Home servers can respond to resolve requests for aliases on other domains than their own by using the federation API to ask other domain name home servers.
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 home server 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/api/v1/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"}
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/api/v1/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."}
/join/{roomId} is an alias for /_matrix/client/api/v1/rooms/{roomId}/join.
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/api/v1/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/api/v1/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/api/v1/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/api/v1/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/api/v1/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/api/v1/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/api/v1/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/api/v1/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 home server when a user successfully changes their display name or avatar URL fields.
Additionally, when home servers 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.
Home servers 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.
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 MUST have the following additional field.
| Key | Type | Description |
|---|---|---|
| event_id | string | The globally unique event identifier. |
| room_id | string | The ID of the room associated with this event. |
| user_id | string | Contains the fully-qualified ID of the user who sent this 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 '_'. |
There are a few differences between how events are formatted for sending between servers over federation and how they are formatted for sending between a server and its clients.
Additionally there are a few differences between the format of events in the responses to client APIs with a /v1 prefix and responses APIs with a /v2 prefix.
Events in responses for APIs with the /v2 prefix are generated from an event formatted for federation by:
Events in responses for APIs with the /v1 prefix are generated from an event formatted for the /v2 prefix by:
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "localhost", "type": "m.room.aliases", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.canonical_alias", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.create", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.join_rules", "user_id": "@example:localhost" }
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} |
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. |
| 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"] |
Example:
{ "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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "@alice:localhost", "type": "m.room.member", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.power_levels", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "redacts": "!fukweghifu23:localhost", "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.redaction", "user_id": "@example:localhost" }
Matrix events are represented using JSON objects. If we want to sign JSON events we need to encode the JSON as a binary string. Unfortunately the same JSON can be encoded in different ways by changing how much white space is used or by changing the order of keys within objects. Therefore we have to define an encoding which can be reproduced byte for byte by any JSON library.
We define the canonical JSON encoding for a value to be the shortest UTF-8 JSON encoding with dictionary keys lexicographically sorted by unicode codepoint. Numbers in the JSON must be integers in the range [-(2**53)+1, (2**53)-1].
We pick UTF-8 as the encoding as it should be available to all platforms and JSON received from the network is likely to be already encoded using UTF-8. We sort the keys to give a consistent ordering. We force integers to be in the range where they can be accurately represented using IEEE double precision floating point numbers since a number of JSON libraries represent all numbers using this representation.
import json def canonical_json(value): return json.dumps( value, # Encode code-points outside of ASCII as UTF-8 rather than \u escapes ensure_ascii=False, # Remove unnecessary white space. separators=(',',':'), # Sort the keys of dictionaries. sort_keys=True, # Encode the resulting unicode as UTF-8 bytes. ).encode("UTF-8")
Adapted from the grammar in http://tools.ietf.org/html/rfc7159 removing insignificant whitespace, fractions, exponents and redundant character escapes
value = false / null / true / object / array / number / string false = %x66.61.6c.73.65 null = %x6e.75.6c.6c true = %x<IP_ADDRESS> object = %x7B [ member *( %x2C member ) ] %7D member = string %x3A value array = %x5B [ value *( %x2C value ) ] %5B number = [ %x2D ] int int = %x30 / ( %x31-39 *digit ) digit = %x30-39 string = %x22 *char %x22 char = unescaped / %x5C escaped unescaped = %x20-21 / %x23-5B / %x5D-10FFFF escaped = %x22 ; " quotation mark U+0022 / %x5C ; \ reverse solidus U+005C / %x62 ; b backspace U+0008 / %x66 ; f form feed U+000C / %x6E ; n line feed U+000A / %x72 ; r carriage return U+000D / %x74 ; t tab U+0009 / %x<IP_ADDRESS> (%x30-37 / %x62 / %x65-66) ; u000X / %x<IP_ADDRESS> (%x30-39 / %x61-66) ; u001X
We can now sign a JSON object by encoding it as a sequence of bytes, computing the signature for that sequence and then adding the signature to the original JSON object.
JSON is signed by encoding the JSON object without signatures or keys grouped as unsigned, using the canonical encoding described above. The JSON bytes are then signed using the signature algorithm and the signature encoded using base64 with the padding stripped. The resulting base64 signature is added to an object under the signing key identifier which is added to the signatures object under the name of the server signing it which is added back to the original JSON object along with the unsigned object.
The signing key identifier is the concatenation of the signing algorithm and a key version. The signing algorithm identifies the algorithm used to sign the JSON. The currently support value for signing algorithm is ed25519 as implemented by NACL (http://nacl.cr.yp.to/). The key version is used to distinguish between different signing keys used by the same entity.
The unsigned object and the signatures object are not covered by the signature. Therefore intermediate servers can add unsigned data such as timestamps and additional signatures.
{ "name": "example.org", "signing_keys": { "ed25519:1": "XSl0kuyvrXNj6A+7/tkrB9sxSbRi08Of5uRhxOqZtEQ" }, "unsigned": { "age_ts":<PHONE_NUMBER>00 }, "signatures": { "example.org": { "ed25519:1": "s76RUgajp8w172am0zQb/iPTHsRnb4SkrzGoeCOSFfcBY2V/1c8QfrmdXHpvnc2jK5BD1WiJIxiMW95fMjK7Bw" } } }
def sign_json(json_object, signing_key, signing_name): signatures = json_object.pop("signatures", {}) unsigned = json_object.pop("unsigned", None) signed = signing_key.sign(encode_canonical_json(json_object)) signature_base64 = encode_base64(signed.signature) key_id = "%s:%s" % (signing_key.alg, signing_key.version) signatures.setdefault(signing_name, {})[key_id] = signature_base64 json_object["signatures"] = signatures if unsigned is not None: json_object["unsigned"] = unsigned return json_object
To check if an entity has signed a JSON object a server does the following
Signing events is a more complicated process since servers can choose to redact non-essential parts of an event. Before signing the event it is encoded as Canonical JSON and hashed using SHA-256. The resulting hash is then stored in the event JSON in a hash object under a sha256 key.
def hash_event(event_json_object): # Keys under "unsigned" can be modified by other servers. # They are useful for conveying information like the age of an # event that will change in transit. # Since they can be modifed we need to exclude them from the hash. unsigned = event_json_object.pop("unsigned", None) # Signatures will depend on the current value of the "hashes" key. # We cannot add new hashes without invalidating existing signatures. signatures = event_json_object.pop("signatures", None) # The "hashes" key might contain multiple algorithms if we decide to # migrate away from SHA-2. We don't want to include an existing hash # output in our hash so we exclude the "hashes" dict from the hash. hashes = event_json_object.pop("hashes", {}) # Encode the JSON using a canonical encoding so that we get the same # bytes on every server for the same JSON object. event_json_bytes = encode_canonical_json(event_json_bytes) # Add the base64 encoded bytes of the hash to the "hashes" dict. hashes["sha256"] = encode_base64(sha256(event_json_bytes).digest()) # Add the "hashes" dict back the event JSON under a "hashes" key. event_json_object["hashes"] = hashes if unsigned is not None: event_json_object["unsigned"] = unsigned return event_json_object
The event is then stripped of all non-essential keys both at the top level and within the content object. Any top-level keys not in the following list MUST be removed:
auth_events depth event_id hashes membership origin origin_server_ts prev_events prev_state room_id sender signatures state_key type
A new content object is constructed for the resulting event that contains only the essential keys of the original content object. If the original event lacked a content object at all, a new empty JSON object is created for it.
The keys that are considered essential for the content object depend on the the type of the event. These are:
type is "m.room.aliases": aliases type is "m.room.create": creator type is "m.room.history_visibility": history_visibility type is "m.room.join_rules": join_rule type is "m.room.member": membership type is "m.room.power_levels": ban events events_default kick redact state_default users users_default
The resulting stripped object with the new content object and the original hashes key is then signed using the JSON signing algorithm outlined below:
def sign_event(event_json_object, name, key): # Make sure the event has a "hashes" key. if "hashes" not in event_json_object: event_json_object = hash_event(event_json_object) # Strip all the keys that would be removed if the event was redacted. # The hashes are not stripped and cover all the keys in the event. # This means that we can tell if any of the non-essential keys are # modified or removed. stripped_json_object = strip_non_essential_keys(event_json_object) # Sign the stripped JSON object. The signature only covers the # essential keys and the hashes. This means that we can check the # signature even if the event is redacted. signed_json_object = sign_json(stripped_json_object) # Copy the signatures from the stripped event to the original event. event_json_object["signatures"] = signed_json_oject["signatures"] return event_json_object
Servers can then transmit the entire event or the event with the non-essential keys removed. If the entire event is present, receiving servers can then check the event by computing the SHA-256 of the event, excluding the hash object. If the keys have been redacted, then the hash object is included when calculating the SHA-256 instead.
New hash functions can be introduced by adding additional keys to the hash object. Since the hash object cannot be redacted a server shouldn't allow too many hashes to be listed, otherwise a server might embed illict data within the hash object. For similar reasons a server shouldn't allow hash values that are too long.
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 |
| End-to-End Encryption | Optional | Optional | Optional | Optional | Optional |
| Server Side Search | 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 |
Example:
{ "age": 242352, "content": { "body": "This is an example text message", "msgtype": "m.text" }, "event_id": "$WLGTSEFSEF:localhost", "origin_server_ts":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.message.feedback", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.name", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.topic", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "state_key": "", "type": "m.room.avatar", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
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":<PHONE_NUMBER>939, "room_id": "!Cuyf34gef24t:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
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. |
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":<PHONE_NUMBER>653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
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. |
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":<PHONE_NUMBER>653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "type": "m.room.message", "user_id": "@example:localhost" }
This message represents a single video clip.
| Content Key | Type | Description |
|---|---|---|