Federation API

Warning

This API is unstable and will change without warning or discussion while we work towards a r0 release (scheduled for August 2018).

Matrix homeservers use the Federation APIs (also known as server-server APIs) to communicate with each other. Homeservers use these APIs to push messages to each other in real-time, to retrieve historic messages from each other, and to query profile and presence information about users on each other's servers.

The APIs are implemented using HTTPS requests between each of the servers. These HTTPS requests are strongly authenticated using public key signatures at the TLS transport layer and using public key signatures in HTTP Authorization headers at the HTTP layer.

There are three main kinds of communication that occur between homeservers:

Persisted Data Units (PDUs):

These events are broadcast from one homeserver to any others that have joined the same room (identified by Room ID). They are persisted in long-term storage and record the history of messages and state for a room.

Like email, it is the responsibility of the originating server of a PDU to deliver that event to its recipient servers. However PDUs are signed using the originating server's private key so that it is possible to deliver them through third-party servers.

Ephemeral Data Units (EDUs):
These events are pushed between pairs of homeservers. They are not persisted and are not part of the history of a room, nor does the receiving homeserver have to reply to them.
Queries:
These are single request/response interactions between a given pair of servers, initiated by one side sending an HTTPS GET request to obtain some information, and responded by the other. They are not persisted and contain no long-term significant history. They simply request a snapshot state at the instant the query is made.

EDUs and PDUs are further wrapped in an envelope called a Transaction, which is transferred from the origin to the destination homeserver using an HTTPS PUT request.

Table of Contents

1   Changelog

Version: unstable

No significant changes.

This version of the specification is generated from matrix-doc as of Git commit HEAD,ef33c17,dirty.

For the full historical changelog, see https://github.com/matrix-org/matrix-doc/blob/master/changelogs/server_server.rst

1.1   Other versions of this specification

The following other versions are also available, in reverse chronological order:

  • HEAD: Includes all changes since the latest versioned release.

2   Server discovery

2.1   Resolving server names

Each matrix homeserver is identified by a server name consisting of a hostname and an optional port, as described by the grammar. Server names should be resolved to an IP address and port using the following process:

  • If the hostname is an IP literal, then that IP address should be used, together with the given port number, or 8448 if no port is given.

  • Otherwise, if the port is present, then an IP address is discovered by looking up an AAAA or A record for the hostname, and the specified port is used.

  • If the hostname is not an IP literal and no port is given, the server is discovered by first looking up a _matrix._tcp SRV record for the hostname, which may give a hostname (to be looked up using AAAA or A queries) and port. If the SRV record does not exist, then the server is discovered by looking up an AAAA or A record on the hostname and taking the default fallback port number of 8448.

    Homeservers may use SRV records to load balance requests between multiple TLS endpoints or to failover to another endpoint if an endpoint fails.

When making requests to servers, use the hostname of the target server in the Host header, regardless of any hostname given in the SRV record. For example, if the server name is example.org, and the SRV record resolves to matrix.example.org, the Host header in the request should be example.org. If an explicit port was given in the server name, it should be included in the Host header; otherwise, no port number should be given in the Host header.

2.2   Server implementation

2.2.1   GET /_matrix/federation/v1/version

Get the implementation name and version of this homeserver.

Request format:

No parameters

Response format:

Parameter Type Description
server Server  
Server
Parameter Type Description
name string Arbitrary name that identify this implementation.
version string Version of this implementation. The version format depends on the implementation.

Example request:

GET /_matrix/federation/v1/version HTTP/1.1

Response:

Status code 200:

The implementation name and version of this homeserver.

Example

{
  "server": {
    "name": "My_Homeserver_Implementation",
    "version": "ArbitraryVersionNumber"
  }
}

2.3   Retrieving server keys

Note

There was once a "version 1" of the key exchange. It has been removed from the specification due to lack of significance. It may be reviewed here.

Each homeserver publishes its public keys under /_matrix/key/v2/server/{keyId}. Homeservers query for keys by either getting /_matrix/key/v2/server/{keyId} directly or by querying an intermediate notary server using a /_matrix/key/v2/query/{serverName}/{keyId} API. Intermediate notary servers query the /_matrix/key/v2/server/{keyId} API on behalf of another server and sign the response with their own key. A server may query multiple notary servers to ensure that they all report the same public keys.

This approach is borrowed from the Perspectives Project, but modified to include the NACL keys and to use JSON instead of XML. It has the advantage of avoiding a single trust-root since each server is free to pick which notary servers they trust and can corroborate the keys returned by a given notary server by querying other servers.

2.3.1   Publishing Keys

Homeservers publish the allowed TLS fingerprints and signing keys in a JSON object at /_matrix/key/v2/server/{key_id}. The response contains a list of verify_keys that are valid for signing federation requests made by the homeserver and for signing events. It contains a list of old_verify_keys which are only valid for signing events. Finally the response contains a list of TLS certificate fingerprints to validate any connection made to the homeserver.

2.3.1.1   GET /_matrix/key/v2/server/{keyId}

Gets the homeserver's published TLS fingerprints and signing keys. The homeserver may have any number of active keys and may have a number of old keys.

Intermediate notary servers should cache a response for half of its lifetime to avoid serving a stale response. Originating servers should avoid returning responses that expire in less than an hour to avoid repeated reqests for a certificate that is about to expire. Requesting servers should limit how frequently they query for certificates to avoid flooding a server with requests.

If the server fails to respond to this request, intermediate notary servers should continue to return the last response they received from the server so that the signatures of old events can still be checked.

Request format:

Parameter Type Description
path parameters
keyId string Deprecated. Servers should not use this parameter and instead opt to return all keys, not just the requested one. The key ID to look up.

Response format:

Server Keys
Parameter Type Description
server_name string DNS name of the homeserver.
verify_keys {string: Verify Key}

Public keys of the homeserver for verifying digital signatures.

The object's key is the algorithm and version combined (ed25519 being the algorithm and abc123 being the version in the example below). Together, this forms the Key ID. The version must have characters matching the regular expression [a-zA-Z0-9_].

old_verify_keys {string: Old Verify Key}

The public keys that the server used to use and when it stopped using them.

The object's key is the algorithm and version combined (ed25519 being the algorithm and 0ldK3y being the version in the example below). Together, this forms the Key ID. The version must have characters matching the regular expression [a-zA-Z0-9_].

signatures {string: {string: string}} Digital signatures for this object signed using the verify_keys.
tls_fingerprints [TLS Fingerprint] Hashes of X.509 TLS certificates used by this server.
valid_until_ts integer POSIX timestamp when the list of valid keys should be refreshed. Keys used beyond this timestamp are no longer valid.
Verify Key
Parameter Type Description
key string The Unpadded Base64 encoded key.
Old Verify Key
Parameter Type Description
expired_ts integer POSIX timestamp in milliseconds for when this key expired.
key string The Unpadded Base64 encoded key.
TLS Fingerprint
Parameter Type Description
sha256 string The Unpadded Base64 encoded fingerprint.

Example request:

GET /_matrix/key/v2/server/ed25519%3Aabc123 HTTP/1.1

Response:

Status code 200:

The homeserver's keys

Example

{
  "server_name": "example.org",
  "verify_keys": {
    "ed25519:abc123": {
      "key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA"
    }
  },
  "old_verify_keys": {
    "ed25519:0ldk3y": {
      "expired_ts": 1532645052628,
      "key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg"
    }
  },
  "signatures": {
    "example.org": {
      "ed25519:auto2": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
    }
  },
  "tls_fingerprints": [
    {
      "sha256": "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw"
    }
  ],
  "valid_until_ts": 1652262000000
}

2.3.2   Querying Keys Through Another Server

Servers may query another server's keys through a notary server. The notary server may be another homeserver. The notary server will retrieve keys from the queried servers through use of the /_matrix/key/v2/server/{keyId} API. The notary server will additionally sign the response from the queried server before returning the results.

Notary servers can return keys for servers that are offline or having issues serving their own keys by using cached responses. Keys can be queried from multiple servers to mitigate against DNS spoofing.

2.3.2.1   GET /_matrix/key/v2/query/{serverName}/{keyId}

Query for another server's keys. The receiving (notary) server must sign the keys returned by the queried server.

Request format:

Parameter Type Description
query parameters
minimum_valid_until_ts integer

A millisecond POSIX timestamp in milliseconds indicating when the returned certificates will need to be valid until to be useful to the requesting server.

If not supplied, the current time as determined by the notary server is used.

path parameters
serverName string Required. The server's DNS name to query
keyId string Deprecated. Servers should not use this parameter and instead opt to return all keys, not just the requested one. The key ID to look up.

Response format:

Parameter Type Description
server_keys [Server Keys] The queried server's keys, signed by the notary server.
Server Keys
Parameter Type Description
server_name string DNS name of the homeserver.
verify_keys {string: Verify Key}

Public keys of the homeserver for verifying digital signatures.

The object's key is the algorithm and version combined (ed25519 being the algorithm and abc123 being the version in the example below). Together, this forms the Key ID. The version must have characters matching the regular expression [a-zA-Z0-9_].

old_verify_keys {string: Old Verify Key}

The public keys that the server used to use and when it stopped using them.

The object's key is the algorithm and version combined (ed25519 being the algorithm and 0ldK3y being the version in the example below). Together, this forms the Key ID. The version must have characters matching the regular expression [a-zA-Z0-9_].

signatures {string: {string: string}} Digital signatures for this object signed using the verify_keys.
tls_fingerprints [TLS Fingerprint] Hashes of X.509 TLS certificates used by this server.
valid_until_ts integer POSIX timestamp when the list of valid keys should be refreshed. Keys used beyond this timestamp are no longer valid.
Verify Key
Parameter Type Description
key string The Unpadded Base64 encoded key.
Old Verify Key
Parameter Type Description
expired_ts integer POSIX timestamp in milliseconds for when this key expired.
key string The Unpadded Base64 encoded key.
TLS Fingerprint
Parameter Type Description
sha256 string The Unpadded Base64 encoded fingerprint.

Example request:

GET /_matrix/key/v2/query/matrix.org/ed25519%3Aabc123?minimum_valid_until_ts=1234567890 HTTP/1.1

Response:

Status code 200:

The keys for the server, or an empty array if the server could not be reached and no cached keys were available.

Example

{
  "server_keys": [
    {
      "server_name": "example.org",
      "verify_keys": {
        "ed25519:abc123": {
          "key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA"
        }
      },
      "old_verify_keys": {
        "ed25519:0ldk3y": {
          "expired_ts": 1532645052628,
          "key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg"
        }
      },
      "signatures": {
        "example.org": {
          "ed25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
        },
        "notary.server.com": {
          "ed25519:010203": "VGhpcyBpcyBhbm90aGVyIHNpZ25hdHVyZQ"
        }
      },
      "tls_fingerprints": [
        {
          "sha256": "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw"
        }
      ],
      "valid_until_ts": 1652262000000
    }
  ]
}

2.3.2.2   POST /_matrix/key/v2/query

Query for keys from multiple servers in a batch format. The receiving (notary) server must sign the keys returned by the queried servers.

Request format:

Parameter Type Description
JSON body parameters
server_keys {string: {string: Query Criteria}}

Required. The query criteria. The outer string key on the object is the server name (eg: matrix.org). The inner string key is the Key ID to query for the particular server. If no key IDs are given to be queried, the notary server should query for all keys. If no servers are given, the notary server must return an empty server_keys array in the response.

The notary server may return multiple keys regardless of the Key IDs given.

Query Criteria
Parameter Type Description
minimum_valid_until_ts integer

A millisecond POSIX timestamp in milliseconds indicating when the returned certificates will need to be valid until to be useful to the requesting server.

If not supplied, the current time as determined by the notary server is used.

Response format:

Parameter Type Description
server_keys [Server Keys] The queried server's keys, signed by the notary server.
Server Keys
Parameter Type Description
server_name string DNS name of the homeserver.
verify_keys {string: Verify Key}

Public keys of the homeserver for verifying digital signatures.

The object's key is the algorithm and version combined (ed25519 being the algorithm and abc123 being the version in the example below). Together, this forms the Key ID. The version must have characters matching the regular expression [a-zA-Z0-9_].

old_verify_keys {string: Old Verify Key}

The public keys that the server used to use and when it stopped using them.

The object's key is the algorithm and version combined (ed25519 being the algorithm and 0ldK3y being the version in the example below). Together, this forms the Key ID. The version must have characters matching the regular expression [a-zA-Z0-9_].

signatures {string: {string: string}} Digital signatures for this object signed using the verify_keys.
tls_fingerprints [TLS Fingerprint] Hashes of X.509 TLS certificates used by this server.
valid_until_ts integer POSIX timestamp when the list of valid keys should be refreshed. Keys used beyond this timestamp are no longer valid.
Verify Key
Parameter Type Description
key string The Unpadded Base64 encoded key.
Old Verify Key
Parameter Type Description
expired_ts integer POSIX timestamp in milliseconds for when this key expired.
key string The Unpadded Base64 encoded key.
TLS Fingerprint
Parameter Type Description
sha256 string The Unpadded Base64 encoded fingerprint.

Example request:

POST /_matrix/key/v2/query HTTP/1.1
Content-Type: application/json

{
  "server_keys": {
    "example.org": {
      "ed25519:abc123": {
        "minimum_valid_until_ts": 1234567890
      }
    }
  }
}

Response:

Status code 200:

The keys for the queried servers, signed by the notary server. Servers which are offline and have no cached keys will not be included in the result. This may result in an empty array.

Example

{
  "server_keys": [
    {
      "server_name": "example.org",
      "verify_keys": {
        "ed25519:abc123": {
          "key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA"
        }
      },
      "old_verify_keys": {
        "ed25519:0ldk3y": {
          "expired_ts": 1532645052628,
          "key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg"
        }
      },
      "signatures": {
        "example.org": {
          "ed25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
        },
        "notary.server.com": {
          "ed25519:010203": "VGhpcyBpcyBhbm90aGVyIHNpZ25hdHVyZQ"
        }
      },
      "tls_fingerprints": [
        {
          "sha256": "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw"
        }
      ],
      "valid_until_ts": 1652262000000
    }
  ]
}

3   Authentication

3.1   Request Authentication

Every HTTP request made by a homeserver is authenticated using public key digital signatures. The request method, target and body are signed by wrapping them in a JSON object and signing it using the JSON signing algorithm. The resulting signatures are added as an Authorization header with an auth scheme of X-Matrix. Note that the target field should include the full path starting with /_matrix/..., including the ? and any query parameters if present, but should not include the leading https:, nor the destination server's hostname.

Step 1 sign JSON:

 {
     "method": "GET",
     "uri": "/target",
     "origin": "origin.hs.example.com",
     "destination": "destination.hs.example.com",
     "content": <request body>,
     "signatures": {
         "origin.hs.example.com": {
             "ed25519:key1": "ABCDEF..."
         }
     }
}

Step 2 add Authorization header:

GET /target HTTP/1.1
Authorization: X-Matrix origin=origin.example.com,key="ed25519:key1",sig="ABCDEF..."
Content-Type: application/json

<JSON-encoded request body>

Example python code:

def authorization_headers(origin_name, origin_signing_key,
                          destination_name, request_method, request_target,
                          content=None):
    request_json = {
         "method": request_method,
         "uri": request_target,
         "origin": origin_name,
         "destination": destination_name,
    }

    if content_json is not None:
        request["content"] = content

    signed_json = sign_json(request_json, origin_name, origin_signing_key)

    authorization_headers = []

    for key, sig in signed_json["signatures"][origin_name].items():
        authorization_headers.append(bytes(
            "X-Matrix origin=%s,key=\"%s\",sig=\"%s\"" % (
                origin_name, key, sig,
            )
        ))

    return ("Authorization", authorization_headers)

3.2   Response Authentication

Responses are authenticated by the TLS server certificate. A homeserver should not send a request until it has authenticated the connected server to avoid leaking messages to eavesdroppers.

3.3   Client TLS Certificates

Requests are authenticated at the HTTP layer rather than at the TLS layer because HTTP services like Matrix are often deployed behind load balancers that handle the TLS and these load balancers make it difficult to check TLS client certificates.

A homeserver may provide a TLS client certificate and the receiving homeserver may check that the client certificate matches the certificate of the origin homeserver.

4   Transactions

The transfer of EDUs and PDUs between homeservers is performed by an exchange of Transaction messages, which are encoded as JSON objects, passed over an HTTP PUT request. A Transaction is meaningful only to the pair of homeservers that exchanged it; they are not globally-meaningful.

Transactions are limited in size; they can have at most 50 PDUs and 100 EDUs.

4.1   PUT /_matrix/federation/v1/send/{txnId}

Push messages representing live activity to another server. The destination name will be set to that of the receiving server itself. Each embedded PDU in the transaction body will be processed.

The sending server must wait and retry for a 200 OK response before sending a transaction with a different txnId to the receiving server.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
origin string Required. The server_name of the homeserver sending this transaction.
origin_server_ts integer Required. POSIX timestamp in milliseconds on originating homeserver when this transaction started.
pdus [Persistent Data Unit] Required. List of persistent updates to rooms. Must not include more than 50 PDUs.
edus [Ephemeral Data Unit] List of ephemeral messages. May be omitted if there are no ephemeral messages to be sent. Must not include more than 100 EDUs.
path parameters
txnId string Required. The transaction ID.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.
Ephemeral Data Unit
Parameter Type Description
edu_type string Required. The type of ephemeral message.
content object Required. The content of the ephemeral message.

Response format:

Parameter Type Description
<body> [integer, PDU Processing Results]  
PDU Processing Results
Parameter Type Description
pdus {string: PDU Processing Result} Required. The PDUs from the original transaction. The string key represents the ID of the PDU (event) that was processed.
PDU Processing Result
Parameter Type Description
error string A human readable description about what went wrong in processing this PDU. If no error is present, the PDU can be considered successfully handled.

Example request:

PUT /_matrix/federation/v1/send/S0meTransacti0nId HTTP/1.1
Content-Type: application/json

{
  "origin": "example.org",
  "origin_server_ts": 1532991320875,
  "pdus": [
    {
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "room_id": "!abc123:matrix.org",
      "sender": "@someone:matrix.org",
      "origin": "matrix.org",
      "origin_server_ts": 1234567890,
      "type": "m.room.message",
      "state_key": "my_key",
      "content": {
        "key": "value"
      },
      "prev_events": [
        [
          "$abc123:matrix.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "depth": 12,
      "auth_events": [
        [
          "$abc123:matrix.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "redacts": "$def456:matrix.org",
      "unsigned": {
        "key": "value"
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ],
  "edus": [
    {
      "edu_type": "m.presence",
      "content": {
        "key": "value"
      }
    }
  ]
}

Response:

Status code 200:

The result of processing the transaction. The server is to use this response even in the event of one or more PDUs failing to be processed.

Example

[
  200,
  {
    "pdus": {
      "$successful_event:example.org": {},
      "$failed_event:example.org": {
        "error": "You are not allowed to send a message to this room."
      }
    }
  }
]

5   PDUs

Each PDU contains a single Room Event which the origin server wants to send to the destination.

The prev_events field of a PDU identifies the "parents" of the event, and thus establishes a partial ordering on events within the room by linking them into a Directed Acyclic Graph (DAG). The sending server should populate this field with all of the events in the room for which it has not yet seen a child - thus demonstrating that the event comes after all other known events.

For example, consider a room whose events form the DAG shown below. A server creating a new event in this room should populate the new event's prev_events field with E4 and E5, since neither event yet has a child:

    E1
    ^
    |
+-> E2 <-+
|        |
E3       E5
^
|
E4

The auth_events field of a PDU identifies the set of events which give the sender permission to send the event. The auth_events for the m.room.create event in a room is empty; for other events, it should be the following subset of the room state:

  • The m.room.create event.

  • The current m.room.power_levels event, if any.

  • The sender's current m.room.member event, if any.

  • If type is m.room.member:

    • The target's current m.room.member event, if any.
    • If membership is join or invite, the current m.room.join_rules event, if any.
    • If membership is invite and content contains a third_party_invite property, the current m.room.third_party_invite event with state_key matching content.third_party_invite.signed.token, if any.

5.1   Persistent Data Unit schema

A persistent data unit (event)

Persistent Data Unit

Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.

Example Unsigned Data

Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.

Event Hash

Parameter Type Description
sha256 string Required. The hash.

Example:

{
    "auth_events": [
        [
            "$abc123:matrix.org",
            {
                "sha256": "abase64encodedsha256hashshouldbe43byteslong"
            }
        ]
    ],
    "content": {
        "key": "value"
    },
    "depth": 12,
    "event_id": "$a4ecee13e2accdadf56c1025:example.com",
    "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
    },
    "origin": "matrix.org",
    "origin_server_ts": 1234567890,
    "prev_events": [
        [
            "$abc123:matrix.org",
            {
                "sha256": "abase64encodedsha256hashshouldbe43byteslong"
            }
        ]
    ],
    "redacts": "$def456:matrix.org",
    "room_id": "!abc123:matrix.org",
    "sender": "@someone:matrix.org",
    "signatures": {
        "example.com": {
            "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
    },
    "state_key": "my_key",
    "type": "m.room.message",
    "unsigned": {
        "key": "value"
    }
}

5.2   Authorization of PDUs

Whenever a server receives an event from a remote server, the receiving server must check that the event is allowed by the authorization rules. These rules depend on the state of the room at that event.

5.2.1   Definitions

Required Power Level
A given event type has an associated required power level. This is given by the current m.room.power_levels event. The event type is either listed explicitly in the events section or given by either state_default or events_default depending on if the event is a state event or not.
Invite Level, Kick Level, Ban Level, Redact Level
The levels given by the invite, kick, ban, and redact properties in the current m.room.power_levels state. Each defaults to 50 if unspecified.
Target User
For an m.room.member state event, the user given by the state_key of the event.

5.2.2   Rules

The rules governing whether an event is authorized depend solely on the state of the room at the point in the room graph at which the new event is to be inserted. The types of state events that affect authorization are:

  • m.room.create
  • m.room.member
  • m.room.join_rules
  • m.room.power_levels
  • m.room.third_party_invite

The rules are as follows:

  1. If type is m.room.create:
    1. If it has any previous events, reject.
    2. If the domain of the room_id does not match the domain of the sender, reject.
    3. If content.room_version is present and is not a recognised version, reject.
    4. If content has no creator field, reject.
    5. Otherwise, allow.
  2. Reject if event has auth_events that:
    1. have duplicate entries for a given type and state_key pair
    2. have entries whose type and state_key don't match those specified by the auth events selection algorithm described above.
  3. If event does not have a m.room.create in its auth_events, reject.
  4. If type is m.room.aliases:
    1. If event has no state_key, reject.
    2. If sender's domain doesn't matches state_key, reject.
    3. Otherwise, allow.
  5. If type is m.room.member:
    1. If no state_key key or membership key in content, reject.
    2. If membership is join:
      1. If the only previous event is an m.room.create and the state_key is the creator, allow.
      2. If the sender does not match state_key, reject.
      3. If the sender is banned, reject.
      4. If the join_rule is invite then allow if membership state is invite or join.
      5. If the join_rule is public, allow.
      6. Otherwise, reject.
    3. If membership is invite:
      1. If content has third_party_invite key:
        1. If target user is banned, reject.
        2. If content.third_party_invite does not have a signed key, reject.
        3. If signed does not have mxid and token keys, reject.
        4. If mxid does not match state_key, reject.
        5. If there is no m.room.third_party_invite event in the current room state with state_key matching token, reject.
        6. If sender does not match sender of the m.room.third_party_invite, reject.
        7. If any signature in signed matches any public key in the m.room.third_party_invite event, allow. The public keys are in content of m.room.third_party_invite as:
          1. A single public key in the public_key field.
          2. A list of public keys in the public_keys field.
        8. Otherwise, reject.
      2. If the sender's current membership state is not join, reject.
      3. If target user's current membership state is join or ban, reject.
      4. If the sender's power level is greater than or equal to the invite level, allow.
      5. Otherwise, reject.
    4. If membership is leave:
      1. If the sender matches state_key, allow if and only if that user's current membership state is invite or join.
      2. If the sender's current membership state is not join, reject.
      3. If the target user's current membership state is ban, and the sender's power level is less than the ban level, reject.
      4. If the sender's power level is greater than or equal to the kick level, and the target user's power level is less than the sender's power level, allow.
      5. Otherwise, reject.
    5. If membership is ban:
      1. If the sender's current membership state is not join, reject.
      2. If the sender's power level is greater than or equal to the ban level, and the target user's power level is less than the sender's power level, allow.
      3. Otherwise, reject.
    6. Otherwise, the membership is unknown. Reject.
  6. If the sender's current membership state is not join, reject.
  7. If type is m.room.third_party_invite:
    1. Allow if and only if sender's current power level is greater than or equal to the invite level.
  8. If the event type's required power level is greater than the sender's power level, reject.
  9. If the event has a state_key that starts with an @ and does not match the sender, reject.
  10. If type is m.room.power_levels:
    1. If users key in content is not a dictionary with keys that are valid user IDs with values that are integers (or a string that is an integer), reject.
    2. If there is no previous m.room.power_levels event in the room, allow.
    3. For each of the keys users_default, events_default, state_default, ban, redact, kick, invite, as well as each entry being changed under the events or users keys:
      1. If the current value is higher than the sender's current power level, reject.
      2. If the new value is higher than the sender's current power level, reject.
    4. For each entry being changed under the users key, other than the sender's own entry:
      1. If the current value is equal to the sender's current power level, reject.
    5. Otherwise, allow.
  11. If type is m.room.redaction:
    1. If the sender's power level is greater than or equal to the redact level, allow.
    2. If the domain of the event_id of the event being redacted is the same as the domain of the event_id of the m.room.redaction, allow.
    3. Otherwise, reject.
  12. Otherwise, allow.

Note

Some consequences of these rules:

  • Unless you are a member of the room, the only permitted operations (apart from the intial create/join) are: joining a public room; accepting or rejecting an invitation to a room.
  • To unban somebody, you must have power level greater than or equal to both the kick and ban levels, and greater than the target user's power level.

5.2.3   Rejection

If an event is rejected it should neither be relayed to clients nor be included as a prev event in any new events generated by the server. Subsequent events from other servers that reference rejected events should be allowed if they still pass the auth rules. The state used in the checks should be calculated as normal, except not updating with the rejected event where it is a state event.

If an event in an incoming transaction is rejected, this should not cause the transaction request to be responded to with an error response.

Note

This means that events may be included in the room DAG even though they should be rejected.

Note

This is in contrast to redacted events which can still affect the state of the room. For example, a redacted join event will still result in the user being considered joined.

5.2.4   Soft failure

Rationale

It is important that we prevent users from evading bans (or other power restrictions) by creating events which reference old parts of the DAG. For example, a banned user could continue to send messages to a room by having their server send events which reference the event before they were banned. Note that such events are entirely valid, and we cannot simply reject them, as it is impossible to distinguish such an event from a legitimate one which has been delayed. We must therefore accept such events and let them participate in state resolution and the federation protocol as normal. However, servers may choose not to send such events on to their clients, so that end users won't actually see the events.

When this happens it is often fairly obvious to servers, as they can see that the new event doesn't actually pass auth based on the "current state" (i.e. the resolved state across all forward extremities). While the event is technically valid, the server can choose to not notify clients about the new event.

This discourages servers from sending events that evade bans etc. in this way, as end users won't actually see the events.

When the homeserver receives a new event over federation it should also check whether the event passes auth checks based on the current state of the room (as well as based on the state at the event). If the event does not pass the auth checks based on the current state of the room (but does pass the auth checks based on the state at that event) it should be "soft failed".

When an event is "soft failed" it should not be relayed to the client nor be referenced by new events created by the homeserver (i.e. they should not be added to the server's list of forward extremities of the room). Soft failed events are otherwise handled as usual.

Note

Soft failed events participate in state resolution as normal if further events are received which reference it. It is the job of the state resolution algorithm to ensure that malicious events cannot be injected into the room state via this mechanism.

Note

Because soft failed state events participate in state resolution as normal, it is possible for such events to appear in the current state of the room. In that case the client should be told about the soft failed event in the usual way (e.g. by sending it down in the state section of a sync response).

Note

A soft failed event should be returned in response to federation requests where appropriate (e.g. in /event/<event_id>). Note that soft failed events are returned in /backfill and /get_missing_events responses only if the requests include events referencing the soft failed events.

Example

As an example consider the event graph:

  A
 /
B

where B is a ban of a user X. If the user X tries to set the topic by sending an event C while evading the ban:

  A
 / \
B   C

servers that receive C after B should soft fail event C, and so will neither relay C to its clients nor send any events referencing C.

If later another server sends an event D that references both B and C (this can happen if it received C before B):

  A
 / \
B   C
 \ /
  D

then servers will handle D as normal. D is sent to the servers' clients (assuming D passes auth checks). The state at D may resolve to a state that includes C, in which case clients should also to be told that the state has changed to include C. (Note: This depends on the exact state resolution algorithm used. In the original version of the algorithm C would be in the resolved state, whereas in latter versions the algorithm tries to prioritise the ban over the topic change.)

Note that this is essentially equivalent to the situation where one server doesn't receive C at all, and so asks another server for the state of the C branch.

Let's go back to the graph before D was sent:

  A
 / \
B   C

If all the servers in the room saw B before C and so soft fail C, then any new event D' will not reference C:

  A
 / \
B   C
|
D

5.2.5   Retrieving event authorization information

The homeserver may be missing event authorization information, or wish to check with other servers to ensure it is receiving the correct auth chain. These APIs give the homeserver an avenue for getting the information it needs.

5.2.5.1   GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}

Retrieves the complete auth chain for a given event.

Requires auth:Yes.

Request format:

Parameter Type Description
path parameters
roomId string Required. The room ID to get the auth chain for.
eventId string Required. The event ID to get the auth chain of.

Response format:

Parameter Type Description
auth_chain [Persistent Data Unit] Required. The full set of authorization events that make up the state of the room, and their authorization events, recursively.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Example request:

GET /_matrix/federation/v1/event_auth/%21abc123%3Amatrix.org/%24helloworld%3Aexample.org HTTP/1.1

Response:

Status code 200:

The auth chain for the event.

Example

{
  "auth_chain": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ]
}

5.2.5.2   POST /_matrix/federation/v1/query_auth/{roomId}/{eventId}

Compares the auth chain provided with what the receiving server has for the room ID and event ID combination.

The auth difference can be calculated in two parts, where the "remote auth" is the auth chain provided by the sending server and the "local auth" is the auth chain the receiving server has. With those lists, the algorithm works bottom-up after sorting each chain by depth then by event ID. The differences are then discovered and returned as the response to this API call.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
auth_chain [Persistent Data Unit] Required. The auth chain (the "remote auth").
missing [string] A list of event IDs that the sender thinks the receiver is missing.
rejects {string: Rejection Reason}

The set of events that the sending server has rejected from the provided auth chain.

The string key is the event ID that was rejected.

path parameters
roomId string Required. The room ID to compare the auth chain in.
eventId string Required. The event ID to compare the auth chain of.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.
Rejection Reason
Parameter Type Description
reason enum Required. The reason for the event being rejected. One of: ["auth_error", "replaced", "not_ancestor"]

Response format:

Parameter Type Description
auth_chain [Persistent Data Unit] Required. The auth chain the receiver has, and used to determine the auth chain differences (the "local auth").
missing [string] Required. The list of event IDs that the receiver believes it is missing, after comparing the "remote auth" and "local auth" chains.
rejects {string: Rejection Reason}

Required. The set of events that the receiving server has rejected from the auth chain, not including events that the sending server is missing as determined from the difference algorithm.

The string key is the event ID that was rejected.

Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.
Rejection Reason
Parameter Type Description
reason enum Required. The reason for the event being rejected. One of: ["auth_error", "replaced", "not_ancestor"]

Example request:

POST /_matrix/federation/v1/query_auth/%21abc123%3Amatrix.org/%24helloworld%3Aexample.org HTTP/1.1
Content-Type: application/json

{
  "auth_chain": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ],
  "missing": [],
  "rejects": {
    "$some_event:example.org": {
      "reason": "auth_error"
    }
  }
}

Response:

Status code 200:

The auth chain differences, as determined by the receiver.

Example

{
  "auth_chain": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ],
  "missing": [
    "$a_missing_event:example.org"
  ],
  "rejects": {
    "$some_event:example.org": {
      "reason": "auth_error"
    }
  }
}

6   EDUs

EDUs, by comparison to PDUs, do not have an ID, a room ID, or a list of "previous" IDs. They are intended to be non-persistent data such as user presence, typing notifications, etc.

6.1   Ephemeral Data Unit schema

An ephemeral data unit.

Ephemeral Data Unit

Parameter Type Description
edu_type string Required. The type of ephemeral message.
content object Required. The content of the ephemeral message.

Example:

{
    "content": {
        "key": "value"
    },
    "edu_type": "m.presence"
}

7   Room State Resolution

The state of a room is a map of (event_type, state_key) to event_id. Each room starts with an empty state, and each state event which is accepted into the room updates the state of that room.

Where each event has a single prev_event, it is clear what the state of the room after each event should be. However, when two branches in the event graph merge, the state of those branches might differ, so a state resolution algorithm must be used to determine the resultant state.

For example, consider the following event graph (where the oldest event, E0, is at the top):

  E0
  |
  E1
 /  \
E2  E4
|    |
E3   |
 \  /
  E5

Suppose E3 and E4 are both m.room.name events which set the name of the room. What should the name of the room be at E5?

Servers should follow one of the following recursively-defined algorithms, depending on the room version, to determine the room state at a given point on the DAG.

7.1   State resolution algorithm for version 2 rooms

The room state S’(E) after an event E is defined in terms of the room state S(E) before E, and depends on whether E is a state event or a message event:

  • If E is a message event, then S’(E) = S(E).
  • If E is a state event, then S’(E) is S(E), except that its entry corresponding to E's event_type and state_key is replaced by E's event_id.

The room state S(E) before E is the resolution of the set of states {S’(E1), S’(E2), …} consisting of the states after each of E's prev_events {E1, E2, …}, where the resolution of a set of states is given in the algorithm below.

7.1.1   Definitions

The state resolution algorithm for version 2 rooms uses the following definitions, given the set of room states {S1, S2, …}:

Power events
A power event is a state event with type m.room.power_levels or m.room.join_rules, or a state event with type m.room.member where the membership is leave or ban and the sender does not match the state_key. The idea behind this is that power events are events that have may remove someone's ability to do something in the room.
Unconflicted state map and conflicted state set
The unconflicted state map is the state where the value of each key exists and is the same in each state Si. The conflicted state set is the set of all other state events. Note that the unconflicted state map only has one event per (event_type, state_key), whereas the conflicted state set may have multiple events.
Auth difference
The auth difference is calculated by first calculating the full auth chain for each state Si, that is the union of the auth chains for each event in Si, and then taking every event that doesn't appear in every auth chain. If Ci is the full auth chain of Si, then the auth difference is Ci − ∩Ci.
Full conflicted set
The full conflicted set is the union of the conflicted state set and the auth difference.
Reverse topological power ordering

The reverse topological power ordering of a set of events is the lexicographically smallest topological ordering based on the DAG formed by auth events. The reverse topological power ordering is ordered from earliest event to latest. For comparing two topological orderings to determine which is the lexicographically smallest, the following comparison relation on events is used: for events x and y, x < y if

  1. x's sender has greater power level than y's sender, when looking at their respective auth_events; or
  2. the senders have the same power level, but x's origin_server_ts is less than y's origin_server_ts; or
  3. the senders have the same power level and the events have the same origin_server_ts, but x's event_id is less than y's event_id.

The reverse topological power ordering can be found by sorting the events using Kahn's algorithm for topological sorting, and at each step selecting, among all the candidate vertices, the smallest vertex using the above comparison relation.

Mainline ordering

Given an m.room.power_levels event P, the mainline of P is the list of events generated by starting with P and recursively taking the m.room.power_levels events from the auth_events, ordered such that P is last. Given another event e, the closest mainline event to e is the first event encountered in the mainline when iteratively descending through the m.room.power_levels events in the auth_events starting at e. If no mainline event is encountered when iteratively descending through the m.room.power_levels events, then the closest mainline event to e can be considered to be a dummy event that is before any other event in the mainline of P for the purposes of condition 1 below.

The mainline ordering based on P of a set of events is the ordering, from smallest to largest, using the following comparision relation on events: for events x and y, x < y if

  1. the closest mainline event to x appears before the closest mainline event to y; or
  2. the closest mainline events are the same, but x's origin_server_ts is less than y's origin_server_ts; or
  3. the closest mainline events are the same and the events have the same origin_server_ts, but x's event_id is less than y's event_id.
Iterative auth checks
The iterative auth checks algorithm takes as input an initial room state and a sorted list of state events, and constructs a new room state by iterating through the event list and applying the state event to the room state if the state event is allowed by the authorization rules. If the state event is not allowed by the authorization rules, then the event is ignored. If a (event_type, state_key) key that is required for checking the authorization rules is not present in the state, then the appropriate state event from the event's auth_events is used.

7.1.2   Algorithm

The resolution of a set of states is obtained as follows:

  1. Take all power events and any events in their auth chains, recursively, that appear in the full conflicted set and order them by the reverse topological power ordering.
  2. Apply the iterative auth checks algorithm on the unconflicted state map and the list of events from the previous step to get a partially resolved state.
  3. Take all remaining events that weren't picked in step 1 and order them by the mainline ordering based on the power level in the partially resolved state obtained in step 2.
  4. Apply the iterative auth checks algorithm on the partial resolved state and the list of events from the previous step.
  5. Update the result by replacing any event with the event with the same key from the unconflicted state map, if such an event exists, to get the final resolved state.

7.2   State resolution algorithm for version 1 rooms

Warning

This section documents the state resolution algorithm as implemented by Synapse as of December 2017 (and therefore the de-facto Matrix protocol). However, this algorithm is known to have some problems.

The room state S’(E) after an event E is defined in terms of the room state S(E) before E, and depends on whether E is a state event or a message event:

  • If E is a message event, then S’(E) = S(E).
  • If E is a state event, then S’(E) is S(E), except that its entry corresponding to E's event_type and state_key is replaced by E's event_id.

The room state S(E) before E is the resolution of the set of states {S’(E’), S’(E’’), …} consisting of the states after each of E's prev_events {E’, E’’, …}.

The resolution of a set of states is defined as follows. The resolved state is built up in a number of passes; here we use R to refer to the results of the resolution so far.

  • Start by setting R to the union of the states to be resolved, excluding any conflicting events.
  • First we resolve conflicts between m.room.power_levels events. If there is no conflict, this step is skipped, otherwise:
    • Assemble all the m.room.power_levels events from the states to be resolved into a list.
    • Sort the list by ascending depth then descending sha1(event_id).
    • Add the first event in the list to R.
    • For each subsequent event in the list, check that the event would be allowed by the authorization rules for a room in state R. If the event would be allowed, then update R with the event and continue with the next event in the list. If it would not be allowed, stop and continue below with m.room.join_rules events.
  • Repeat the above process for conflicts between m.room.join_rules events.
  • Repeat the above process for conflicts between m.room.member events.
  • No other events affect the authorization rules, so for all other conflicts, just pick the event with the highest depth and lowest sha1(event_id) that passes authentication in R and add it to R.

A conflict occurs between states where those states have different event_ids for the same (state_type, state_key). The events thus affected are said to be conflicting events.

8   Backfilling and retrieving missing events

Once a homeserver has joined a room, it receives all the events emitted by other homeservers in that room, and is thus aware of the entire history of the room from that moment onwards. Since users in that room are able to request the history by the /messages client API endpoint, it's possible that they might step backwards far enough into history before the homeserver itself was a member of that room.

To cover this case, the federation API provides a server-to-server analog of the /messages client API, allowing one homeserver to fetch history from another. This is the /backfill API.

To request more history, the requesting homeserver picks another homeserver that it thinks may have more (most likely this should be a homeserver for some of the existing users in the room at the earliest point in history it has currently), and makes a /backfill request.

Similar to backfilling a room's history, a server may not have all the events in the graph. That server may use the /get_missing_events API to acquire the events it is missing.

8.1   GET /_matrix/federation/v1/backfill/{roomId}

Retrieves a sliding-window history of previous PDUs that occurred in the given room. Starting from the PDU ID(s) given in the v argument, the PDUs that preceded it are retrieved, up to the total number given by the limit.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
v [string] Required. The event IDs to backfill from.
limit integer Required. The maximum number of PDUs to retrieve, including the given events.
path parameters
roomId string Required. The room ID to backfill.

Response format:

Transaction
Parameter Type Description
origin string Required. The server_name of the homeserver sending this transaction.
origin_server_ts integer Required. POSIX timestamp in milliseconds on originating homeserver when this transaction started.
pdus [Persistent Data Unit] Required. List of persistent updates to rooms. Must not include more than 50 PDUs.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Example request:

GET /_matrix/federation/v1/backfill/%21SomeRoom%3Amatrix.org?v=%24abc123%3Amatrix.org&limit=2 HTTP/1.1

Response:

Status code 200:

A transaction containing the PDUs that preceded the given event(s), including the given event(s), up to the given limit.

Example

{
  "origin": "matrix.org",
  "origin_server_ts": 1234567890,
  "pdus": [
    {
      "room_id": "!SomeRoom:matrix.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$abc123:matrix.org",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    },
    {
      "room_id": "!SomeRoom:matrix.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ]
}

8.2   POST /_matrix/federation/v1/get_missing_events/{roomId}

Retrieves previous events that the sender is missing. This is done by doing a breadth-first walk of the prev_events for the latest_events, ignoring any events in earliest_events and stopping at the limit.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
limit integer The maximum number of events to retrieve. Defaults to 10.
min_depth integer The minimum depth of events to retrieve. Defaults to 0.
earliest_events [string] Required. The latest events that the sender already has. These are skipped when retrieving the previous events of latest_events.
latest_events [string] Required. The events to retrieve the previous events for.
path parameters
roomId string Required. The room ID to search in.

Response format:

Parameter Type Description
events [Persistent Data Unit] Required. The missing events.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Example request:

POST /_matrix/federation/v1/get_missing_events/%21SomeRoom%3Amatrix.org HTTP/1.1
Content-Type: application/json

{
  "limit": 10,
  "min_depth": 0,
  "earliest_events": [
    "$missing_event:example.org"
  ],
  "latest_events": [
    "$event_that_has_the_missing_event_as_a_previous_event:example.org"
  ]
}

Response:

Status code 200:

The previous events for latest_events, excluding any earliest_events, up to the provided limit.

Example

{
  "events": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ]
}

9   Retrieving events

In some circumstances, a homeserver may be missing a particular event or information about the room which cannot be easily determined from backfilling. These APIs provide homeservers with the option of getting events and the state of the room at a given point in the timeline.

9.1   GET /_matrix/federation/v1/state/{roomId}

Retrieves a snapshot of a room's state at a given event.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
event_id string Required. An event ID in the room to retrieve the state at.
path parameters
roomId string Required. The room ID to get state for.

Response format:

Parameter Type Description
auth_chain [Persistent Data Unit] Required. The full set of authorization events that make up the state of the room, and their authorization events, recursively.
pdus [Persistent Data Unit] Required. The fully resolved state of the room at the given event.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Example request:

GET /_matrix/federation/v1/state/%21abc123%3Amatrix.org?event_id=%24helloworld%3Amatrix.org HTTP/1.1

Response:

Status code 200:

The fully resolved state for the room, prior to considering any state changes induced by the requested event. Includes the authorization chain for the events.

Example

{
  "auth_chain": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ],
  "pdus": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ]
}

9.2   GET /_matrix/federation/v1/state_ids/{roomId}

Retrieves a snapshot of a room's state at a given event, in the form of event IDs. This performs the same function as calling /state/{roomId}, however this returns just the event IDs rather than the full events.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
event_id string Required. An event ID in the room to retrieve the state at.
path parameters
roomId string Required. The room ID to get state for.

Response format:

Parameter Type Description
auth_chain_ids [string] Required. The full set of authorization events that make up the state of the room, and their authorization events, recursively.
pdu_ids [string] Required. The fully resolved state of the room at the given event.

Example request:

GET /_matrix/federation/v1/state_ids/%21abc123%3Amatrix.org?event_id=%24helloworld%3Amatrix.org HTTP/1.1

Response:

Status code 200:

The fully resolved state for the room, prior to considering any state changes induced by the requested event. Includes the authorization chain for the events.

Example

{
  "auth_chain_ids": [
    "$an_event:example.org"
  ],
  "pdu_ids": [
    "$an_event:example.org"
  ]
}

9.3   GET /_matrix/federation/v1/event/{eventId}

Retrieves a single event.

Requires auth:Yes.

Request format:

Parameter Type Description
path parameters
eventId string Required. The event ID to get.

Response format:

Transaction
Parameter Type Description
origin string Required. The server_name of the homeserver sending this transaction.
origin_server_ts integer Required. POSIX timestamp in milliseconds on originating homeserver when this transaction started.
pdus [Persistent Data Unit] Required. List of persistent updates to rooms. Must not include more than 50 PDUs.
Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The ID of the user sending the event.
origin string Required. The server_name of the homeserver that created this event.
origin_server_ts integer Required. Timestamp in milliseconds on origin homeserver when this event was created.
type string Required. Event type
state_key string If this key is present, the event is a state event, and it will replace previous events with the same type and state_key in the room state.
content object Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. Event IDs and reference hashes for the authorization events that would allow this event to be in the room.
redacts string For redaction events, the ID of the event being redacted.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Example request:

GET /_matrix/federation/v1/event/%24abc123%3Amatrix.org HTTP/1.1

Response:

Status code 200:

A transaction containing a single PDU which is the event requested.

Example

{
  "origin": "matrix.org",
  "origin_server_ts": 1234567890,
  "pdus": [
    {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.message",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "key": "value"
      },
      "unsigned": {
        "age": 4612
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
        }
      }
    }
  ]
}

10   Joining Rooms

When a new user wishes to join a room that the user's homeserver already knows about, the homeserver can immediately determine if this is allowable by inspecting the state of the room. If it is acceptable, it can generate, sign, and emit a new m.room.member state event adding the user into that room. When the homeserver does not yet know about the room it cannot do this directly. Instead, it must take a longer multi-stage handshaking process by which it first selects a remote homeserver which is already participating in that room, and use it to assist in the joining process. This is the remote join handshake.

This handshake involves the homeserver of the new member wishing to join (referred to here as the "joining" server), the directory server hosting the room alias the user is requesting to join with, and a homeserver where existing room members are already present (referred to as the "resident" server).

In summary, the remote join handshake consists of the joining server querying the directory server for information about the room alias; receiving a room ID and a list of join candidates. The joining server then requests information about the room from one of the residents. It uses this information to construct a m.room.member event which it finally sends to a resident server.

Conceptually these are three different roles of homeserver. In practice the directory server is likely to be resident in the room, and so may be selected by the joining server to be the assisting resident. Likewise, it is likely that the joining server picks the same candidate resident for both phases of event construction, though in principle any valid candidate may be used at each time. Thus, any join handshake can potentially involve anywhere from two to four homeservers, though most in practice will use just two.

Client         Joining                Directory       Resident
               Server                 Server          Server

join request -->
               |
               directory request ------->
               <---------- directory response
               |
               make_join request ----------------------->
               <------------------------------- make_join response
               |
               send_join request ----------------------->
               <------------------------------- send_join response
               |
<---------- join response

The first part of the handshake usually involves using the directory server to request the room ID and join candidates through the /query/directory API endpoint. In the case of a new user joining a room as a result of a received invite, the joining user's homeserver could optimise this step away by picking the origin server of that invite message as the join candidate. However, the joining server should be aware that the origin server of the invite might since have left the room, so should be prepared to fall back on the regular join flow if this optimisation fails.

Once the joining server has the room ID and the join candidates, it then needs to obtain enough information about the room to fill in the required fields of the m.room.member event. It obtains this by selecting a resident from the candidate list, and using the GET /make_join endpoint. The resident server will then reply with enough information for the joining server to fill in the event.

The joining server is expected to add or replace the origin, origin_server_ts, and event_id on the templated event received by the resident server. This event is then signed by the joining server.

To complete the join handshake, the joining server must now submit this new event to a resident homeserver, by using the PUT /send_join endpoint.

The resident homeserver then accepts this event into the room's event graph, and responds to the joining server with the full set of state for the newly-joined room. The resident server must also send the event to other servers participating in the room.

10.1   GET /_matrix/federation/v1/make_join/{roomId}/{userId}

Asks the receiving server to return information that the sending server will need to prepare a join event to get into the room.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
ver [string] The room versions the sending server has support for. Defaults to [1].
path parameters
roomId string Required. The room ID that is about to be joined.
userId string Required. The user ID the join event will be for.

Response format:

Parameter Type Description
event Unsigned Persistent Data Unit An unsigned template event.
Unsigned Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The user ID of the joining member.
origin string Required. The name of the resident homeserver.
origin_server_ts integer Required. A timestamp added by the resident homeserver.
type string Required. The value m.room.member.
state_key string Required. The user ID of the joining member.
content Membership Event Content Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. This field must be present but is ignored; it may be 0.
auth_events [[string, Event Hash]] Required. An event reference list containing the authorization events that would allow the member to join the room. This should normally be the m.room.create, m.room.power_levels, and m.room.join_rules events.
redacts string Not used.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
Membership Event Content
Parameter Type Description
membership string Required. The value join.
Event Hash
Parameter Type Description
sha256 string Required. The event hash.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.

Example request:

GET /_matrix/federation/v1/make_join/%21abc123%3Amatrix.org/%40someone%3Aexample.org?ver=1&ver=2 HTTP/1.1

Responses:

Status code 200:

A template to be used for the rest of the Joining Rooms handshake.

Example

{
  "event": {
    "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
    "sender": "@alice:example.com",
    "origin": "example.com",
    "event_id": "$a4ecee13e2accdadf56c1025:example.com",
    "origin_server_ts": 1404838188000,
    "depth": 12,
    "auth_events": [
      [
        "$room_cre4te_3vent:matrix.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ],
      [
        "$room_j0in_rul3s_3vent:matrix.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ],
      [
        "$room_p0wer_l3vels_3vent:matrix.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ]
    ],
    "type": "m.room.member",
    "prev_events": [
      [
        "$af232176:example.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ]
    ],
    "content": {
      "membership": "join"
    },
    "unsigned": {
      "age": 4612
    },
    "state_key": "@someone:example.org"
  }
}

Status code 400:

The request is invalid or the room the server is attempting to join has a version that is not listed in the ver parameters.

The error should be passed through to clients so that they may give better feedback to users.

Example

{
  "errcode": "M_INCOMPATIBLE_ROOM_VERSION",
  "error": "Your homeserver does not support the features required to join this room",
  "room_version": "3"
}

10.2   PUT /_matrix/federation/v1/send_join/{roomId}/{eventId}

Submits a signed join event to the resident server for it to accept it into the room's graph.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The user ID of the joining member.
origin string Required. The name of the joining homeserver.
origin_server_ts integer Required. A timestamp added by the joining homeserver.
type string Required. The value m.room.member.
state_key string Required. The user ID of the joining member.
content Membership Event Content Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. This field must be present but is ignored; it may be 0.
auth_events [[string, Event Hash]] Required. An event reference list containing the authorization events that would allow the member to join the room.
redacts string Not used.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
path parameters
roomId string Required. The room ID that is about to be joined.
eventId string Required. The event ID for the join event.
Membership Event Content
Parameter Type Description
membership string Required. The value join.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Response format:

Parameter Type Description
<body> [integer, Room State]  
Room State
Parameter Type Description
origin string Required. The resident server's DNS name.
auth_chain [object] Required. The auth chain.
state [object] Required. The room state.

Example request:

PUT /_matrix/federation/v1/send_join/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1
Content-Type: application/json

{
  "event_id": "$a4ecee13e2accdadf56c1025:example.com",
  "room_id": "!abc123:matrix.org",
  "sender": "@someone:example.org",
  "origin": "matrix.org",
  "origin_server_ts": 1234567890,
  "type": "m.room.member",
  "state_key": "@someone:example.org",
  "content": {
    "membership": "join"
  },
  "prev_events": [
    [
      "$abc123:matrix.org",
      {
        "sha256": "abase64encodedsha256hashshouldbe43byteslong"
      }
    ]
  ],
  "depth": 12,
  "auth_events": [
    [
      "$abc123:matrix.org",
      {
        "sha256": "abase64encodedsha256hashshouldbe43byteslong"
      }
    ]
  ],
  "redacts": "string",
  "unsigned": {
    "key": "value"
  },
  "hashes": {
    "sha256": "thishashcoversallfieldsincasethisisredacted"
  },
  "signatures": {
    "example.com": {
      "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
    }
  }
}

Response:

Status code 200:

The full state for the room, having accepted the join event.

Example

[
  200,
  {
    "origin": "matrix.org",
    "auth_chain": [
      {
        "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
        "sender": "@alice:example.com",
        "origin": "example.com",
        "event_id": "$a4ecee13e2accdadf56c1025:example.com",
        "origin_server_ts": 1404838188000,
        "depth": 12,
        "auth_events": [
          [
            "$af232176:example.org",
            {
              "sha256": "abase64encodedsha256hashshouldbe43byteslong"
            }
          ]
        ],
        "type": "m.room.message",
        "prev_events": [
          [
            "$af232176:example.org",
            {
              "sha256": "abase64encodedsha256hashshouldbe43byteslong"
            }
          ]
        ],
        "content": {
          "key": "value"
        },
        "unsigned": {
          "age": 4612
        },
        "hashes": {
          "sha256": "thishashcoversallfieldsincasethisisredacted"
        },
        "signatures": {
          "example.com": {
            "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
          }
        }
      }
    ],
    "state": [
      {
        "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
        "sender": "@alice:example.com",
        "origin": "example.com",
        "event_id": "$a4ecee13e2accdadf56c1025:example.com",
        "origin_server_ts": 1404838188000,
        "depth": 12,
        "auth_events": [
          [
            "$af232176:example.org",
            {
              "sha256": "abase64encodedsha256hashshouldbe43byteslong"
            }
          ]
        ],
        "type": "m.room.message",
        "prev_events": [
          [
            "$af232176:example.org",
            {
              "sha256": "abase64encodedsha256hashshouldbe43byteslong"
            }
          ]
        ],
        "content": {
          "key": "value"
        },
        "unsigned": {
          "age": 4612
        },
        "hashes": {
          "sha256": "thishashcoversallfieldsincasethisisredacted"
        },
        "signatures": {
          "example.com": {
            "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
          }
        }
      }
    ]
  }
]

11   Inviting to a room

When a user on a given homeserver invites another user on the same homeserver, the homeserver may sign the membership event itself and skip the process defined here. However, when a user invites another user on a different homeserver, a request to that homeserver to have the event signed and verified must be made.

11.1   PUT /_matrix/federation/v1/invite/{roomId}/{eventId}

Invites a remote user to a room. Once the event has been signed by both the inviting homeserver and the invited homeserver, it can be sent to all of the servers in the room by the inviting homeserver.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The matrix ID of the user who sent the original m.room.third_party_invite.
origin string Required. The name of the inviting homeserver.
origin_server_ts integer Required. A timestamp added by the inviting homeserver.
type string Required. The value m.room.member.
state_key string Required. The user ID of the invited member.
content Membership Event Content Required. The content of the event, matching what is available in the Client-Server API. Must include a membership of invite.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. An event reference list containing the authorization events that would allow the member to be invited to the room.
redacts string Not used.
unsigned Unsigned Event Content Information included alongside the event that is not signed. May include more than what is listed here.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
path parameters
roomId string Required. The room ID that the user is being invited to.
eventId string Required. The event ID for the invite event, generated by the inviting server.
Membership Event Content
Parameter Type Description
membership string Required. The value invite.
Unsigned Event Content
Parameter Type Description
invite_room_state [Invite Room State Event] An optional list of simplified events to help the receiver of the invite identify the room. The recommended events to include are the join rules, canonical alias, avatar, and name of the room.
Invite Room State Event
Parameter Type Description
type string Required. The type of event.
state_key string Required. The state key for the event. May be an empty string.
content object Required. The content for the event.
sender string Required. The sender of the event.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Response format:

Parameter Type Description
<body> [integer, Event Container]  
Event Container
Parameter Type Description
event Invite Event Required. An invite event
Invite Event
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The matrix ID of the user who sent the original m.room.third_party_invite.
origin string Required. The name of the inviting homeserver.
origin_server_ts integer Required. A timestamp added by the inviting homeserver.
type string Required. The value m.room.member.
state_key string Required. The user ID of the invited member.
content Membership Event Content Required. The content of the event, matching what is available in the Client-Server API. Must include a membership of invite.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. An event reference list containing the authorization events that would allow the member to be invited to the room.
redacts string Not used.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
Membership Event Content
Parameter Type Description
membership string Required. The value invite.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Example request:

PUT /_matrix/federation/v1/invite/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1
Content-Type: application/json

{
  "event_id": "$a4ecee13e2accdadf56c1025:example.com",
  "room_id": "!abc123:matrix.org",
  "sender": "@someone:example.org",
  "origin": "matrix.org",
  "origin_server_ts": 1234567890,
  "type": "m.room.member",
  "state_key": "@joe:elsewhere.com",
  "content": {
    "membership": "invite"
  },
  "prev_events": [
    [
      "$abc123:matrix.org",
      {
        "sha256": "abase64encodedsha256hashshouldbe43byteslong"
      }
    ]
  ],
  "depth": 12,
  "auth_events": [
    [
      "$abc123:matrix.org",
      {
        "sha256": "abase64encodedsha256hashshouldbe43byteslong"
      }
    ]
  ],
  "redacts": "string",
  "unsigned": {
    "invite_room_state": [
      {
        "type": "m.room.join_rules",
        "sender": "@someone:matrix.org",
        "state_key": "",
        "content": {
          "join_rule": "public"
        }
      }
    ]
  },
  "hashes": {
    "sha256": "thishashcoversallfieldsincasethisisredacted"
  },
  "signatures": {
    "example.com": {
      "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
    }
  }
}

Responses:

Status code 200:

The event with the invited server's signature added. All other fields of the events should remain untouched.

Example

[
  200,
  {
    "event": {
      "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
      "sender": "@alice:example.com",
      "origin": "example.com",
      "event_id": "$a4ecee13e2accdadf56c1025:example.com",
      "origin_server_ts": 1404838188000,
      "depth": 12,
      "auth_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "type": "m.room.member",
      "prev_events": [
        [
          "$af232176:example.org",
          {
            "sha256": "abase64encodedsha256hashshouldbe43byteslong"
          }
        ]
      ],
      "content": {
        "membership": "invite"
      },
      "unsigned": {
        "invite_room_state": [
          {
            "type": "m.room.join_rules",
            "sender": "@someone:matrix.org",
            "state_key": "",
            "content": {
              "join_rule": "public"
            }
          },
          {
            "type": "m.room.name",
            "sender": "@someone:matrix.org",
            "state_key": "",
            "content": {
              "name": "Cool New Room"
            }
          }
        ]
      },
      "hashes": {
        "sha256": "thishashcoversallfieldsincasethisisredacted"
      },
      "signatures": {
        "example.com": {
          "ed25519:key_version": "SomeSignatureHere"
        },
        "elsewhere.com": {
          "ed25519:k3y_versi0n": "SomeOtherSignatureHere"
        }
      },
      "state_key": "@someone:example.org"
    }
  }
]

Status code 403:

The invite is not allowed. This could be for a number of reasons, including:

  • The sender is not allowed to send invites to the target user/homeserver.
  • The homeserver does not permit anyone to invite its users.
  • The homeserver refuses to participate in the room.

Example

{
  "errcode": "M_FORBIDDEN",
  "error": "User cannot invite the target user."
}

12   Leaving Rooms (Rejecting Invites)

Normally homeservers can send appropriate m.room.member events to have users leave the room, or to reject local invites. Remote invites from other homeservers do not involve the server in the graph and therefore need another approach to reject the invite. Joining the room and promptly leaving is not recommended as clients and servers will interpret that as accepting the invite, then leaving the room rather than rejecting the invite.

Similar to the Joining Rooms handshake, the server which wishes to leave the room starts with sending a /make_leave request to a resident server. In the case of rejecting invites, the resident server may be the server which sent the invite. After receiving a template event from /make_leave, the leaving server signs the event and replaces the event_id with it's own. This is then sent to the resident server via /send_leave. The resident server will then send the event to other servers in the room.

12.1   GET /_matrix/federation/v1/make_leave/{roomId}/{userId}

Asks the receiving server to return information that the sending server will need to prepare a leave event to get out of the room.

Requires auth:Yes.

Request format:

Parameter Type Description
path parameters
roomId string Required. The room ID that is about to be left.
userId string Required. The user ID the leave event will be for.

Response format:

Parameter Type Description
event Unsigned Persistent Data Unit An unsigned template event.
Unsigned Persistent Data Unit
Parameter Type Description
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The user ID of the leaving member.
origin string Required. The name of the resident homeserver.
origin_server_ts integer Required. A timestamp added by the resident homeserver.
type string Required. The value m.room.member.
state_key string Required. The user ID of the leaving member.
content Membership Event Content Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. The maximum depth of the prev_events, plus one. Must be less than the maximum value for an integer (2^63 - 1). If the room's depth is already at the limit, the depth must be set to the limit.
auth_events [[string, Event Hash]] Required. An event reference list containing the authorization events that would allow the member to leave the room. This should normally be the m.room.create, m.room.power_levels, and m.room.join_rules events.
redacts string Not used.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
Membership Event Content
Parameter Type Description
membership string Required. The value leave.
Event Hash
Parameter Type Description
sha256 string Required. The event hash.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.

Example request:

GET /_matrix/federation/v1/make_leave/%21abc123%3Amatrix.org/%40someone%3Aexample.org HTTP/1.1

Responses:

Status code 200:

A template to be used to call /send_leave.

Example

{
  "event": {
    "room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
    "sender": "@alice:example.com",
    "origin": "example.com",
    "event_id": "$a4ecee13e2accdadf56c1025:example.com",
    "origin_server_ts": 1404838188000,
    "depth": 12,
    "auth_events": [
      [
        "$room_cre4te_3vent:matrix.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ],
      [
        "$room_j0in_rul3s_3vent:matrix.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ],
      [
        "$room_p0wer_l3vels_3vent:matrix.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ]
    ],
    "type": "m.room.member",
    "prev_events": [
      [
        "$af232176:example.org",
        {
          "sha256": "abase64encodedsha256hashshouldbe43byteslong"
        }
      ]
    ],
    "content": {
      "membership": "leave"
    },
    "unsigned": {
      "age": 4612
    },
    "state_key": "@someone:example.org"
  }
}

Status code 403:

The request is not authorized. This could mean that the user is not in the room.

Example

{
  "errcode": "M_FORBIDDEN",
  "error": "User is not in the room."
}

12.2   PUT /_matrix/federation/v1/send_leave/{roomId}/{eventId}

Submits a signed leave event to the resident server for it to accept it into the room's graph.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
event_id string Required. The event ID for the PDU.
room_id string Required. Room identifier.
sender string Required. The user ID of the leaving member.
origin string Required. The name of the leaving homeserver.
origin_server_ts integer Required. A timestamp added by the leaving homeserver.
type string Required. The value m.room.member.
state_key string Required. The user ID of the leaving member.
content Membership Event Content Required. The content of the event.
prev_events [[string, Event Hash]] Required. Event IDs and reference hashes for the most recent events in the room that the homeserver was aware of when it made this event.
depth integer Required. This field must be present but is ignored; it may be 0.
auth_events [[string, Event Hash]] Required. An event reference list containing the authorization events that would allow the member to leave the room.
redacts string Not used.
unsigned Example Unsigned Data Additional data added by the origin server but not covered by the signatures. More keys than those defined here may be used.
hashes Event Hash Required. Content hashes of the PDU, following the algorithm specified in Signing Events.
signatures {string: {string: string}} Required. Signatures for the PDU, following the algorithm specified in Signing Events.
path parameters
roomId string Required. The room ID that is about to be left.
eventId string Required. The event ID for the leave event.
Membership Event Content
Parameter Type Description
membership string Required. The value leave.
Example Unsigned Data
Parameter Type Description
age integer The number of milliseconds that have passed since this message was sent.
replaces_state string The event ID of the state event this event replaces.
prev_sender string The sender of the replaced state event.
prev_content object The content of the replaced state event.
redacted_because string A reason for why the event was redacted.
Event Hash
Parameter Type Description
sha256 string Required. The hash.

Response format:

Parameter Type Description
<body> [integer, Empty Object]  

Example request:

PUT /_matrix/federation/v1/send_leave/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1
Content-Type: application/json

{
  "event_id": "$a4ecee13e2accdadf56c1025:example.com",
  "room_id": "!abc123:matrix.org",
  "sender": "@someone:example.org",
  "origin": "matrix.org",
  "origin_server_ts": 1234567890,
  "type": "m.room.member",
  "state_key": "@someone:example.org",
  "content": {
    "membership": "leave"
  },
  "prev_events": [
    [
      "$abc123:matrix.org",
      {
        "sha256": "abase64encodedsha256hashshouldbe43byteslong"
      }
    ]
  ],
  "depth": 12,
  "auth_events": [
    [
      "$abc123:matrix.org",
      {
        "sha256": "abase64encodedsha256hashshouldbe43byteslong"
      }
    ]
  ],
  "redacts": "string",
  "unsigned": {
    "key": "value"
  },
  "hashes": {
    "sha256": "thishashcoversallfieldsincasethisisredacted"
  },
  "signatures": {
    "example.com": {
      "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
    }
  }
}

Response:

Status code 200:

An empty response to indicate the event was accepted into the graph by the receiving homeserver.

Example

[
  200,
  {}
]

13   Third-party invites

Note

More information about third party invites is available in the Client-Server API under the Third Party Invites module.

When an user wants to invite another user in a room but doesn't know the Matrix ID to invite, they can do so using a third-party identifier (e.g. an e-mail or a phone number).

This identifier and its bindings to Matrix IDs are verified by an identity server implementing the Identity Service API.

13.1   Cases where an association exists for a third-party identifier

If the third-party identifier is already bound to a Matrix ID, a lookup request on the identity server will return it. The invite is then processed by the inviting homeserver as a standard m.room.member invite event. This is the simplest case.

13.2   Cases where an association doesn't exist for a third-party identifier

If the third-party identifier isn't bound to any Matrix ID, the inviting homeserver will request the identity server to store an invite for this identifier and to deliver it to whoever binds it to its Matrix ID. It will also send a m.room.third_party_invite event in the room to specify a display name, a token and public keys the identity server provided as a response to the invite storage request.

When a third-party identifier with pending invites gets bound to a Matrix ID, the identity server will send a POST request to the ID's homeserver as described in the Invitation Storage section of the Identity Service API.

The following process applies for each invite sent by the identity server:

The invited homeserver will create a m.room.member invite event containing a special third_party_invite section containing the token and a signed object, both provided by the identity server.

If the invited homeserver is in the room the invite came from, it can auth the event and send it.

However, if the invited homeserver isn't in the room the invite came from, it will need to request the room's homeserver to auth the event.

13.2.1   PUT /_matrix/federation/v1/exchange_third_party_invite/{roomId}

The receiving server will verify the partial m.room.member event given in the request body. If valid, the receiving server will issue an invite as per the Inviting to a room section before returning a response to this request.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
type string Required. The event type. Must be m.room.member
room_id string Required. The room ID the event is for. Must match the ID given in the path.
sender string Required. The user ID of the user who sent the original m.room.third_party_invite event.
state_key string Required. The user ID of the invited user
content Event Content Required. The event content
path parameters
roomId string Required. The room ID to exchange a third party invite in
Event Content
Parameter Type Description
membership string Required. The membership state. Must be invite
third_party_invite NO_TITLE Required. The third party invite
NO_TITLE
Parameter Type Description
signatures {string: {string: string}} Required. The server signatures for this event.
mxid string Required. The invited matrix user ID
token string Required. The token used to verify the event

Example request:

PUT /_matrix/federation/v1/exchange_third_party_invite/%21abc123%3Amatrix.org HTTP/1.1
Content-Type: application/json

{
  "type": "m.room.member",
  "room_id": "!abc123:matrix.org",
  "sender": "@joe:matrix.org",
  "state_key": "@someone:example.org",
  "content": {
    "membership": "invite",
    "third_party_invite": {
      "display_name": "alice",
      "signed": {
        "mxid": "@alice:localhost",
        "token": "abc123",
        "signatures": {
          "magic.forest": {
            "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
          }
        }
      }
    }
  }
}

Response:

Status code 200:

The invite has been issued successfully.

Example

{}

13.2.2   PUT /_matrix/federation/v1/3pid/onbind

Used by identity servers to notify the homeserver that one of its users has bound a third party identifier successfully, including any pending room invites the identity server has been made aware of.

Request format:

Parameter Type Description
JSON body parameters
medium string Required. The type of third party identifier. Currently only "email" is a possible value.
address string Required. The third party identifier itself. For example, an email address.
mxid string Required. The user that is now bound to the third party identifier.
invites [Third Party Invite] Required. A list of pending invites that the third party identifier has received.
Third Party Invite
Parameter Type Description
medium string Required. The type of third party invite issues. Currently only "email" is used.
address string Required. The third party identifier that received the invite.
mxid string Required. The now-bound user ID that received the invite.
room_id string Required. The room ID the invite is valid for.
sender string Required. The user ID that sent the invite.
signed Identity Server Signatures Required. Signature from the identity server using a long-term private key.
Identity Server Signatures
Parameter Type Description
mxid string Required. The user ID that has been bound to the third party identifier.
token string Required. A token.
signatures {string: Identity Server Domain Signature} Required. The signature from the identity server. The string key is the identity server's domain name, such as vector.im
Identity Server Domain Signature
Parameter Type Description
ed25519:0 string Required. The signature.

Example request:

PUT /_matrix/federation/v1/3pid/onbind HTTP/1.1
Content-Type: application/json

{
  "medium": "email",
  "address": "alice@example.com",
  "mxid": "@alice:matrix.org",
  "invites": [
    {
      "medium": "email",
      "address": "alice@example.com",
      "mxid": "@alice:matrix.org",
      "room_id": "!somewhere:example.org",
      "sender": "@bob:matrix.org",
      "signed": {
        "mxid": "@alice:matrix.org",
        "token": "Hello World",
        "signatures": {
          "vector.im": {
            "ed25519:0": "SomeSignatureGoesHere"
          }
        }
      }
    }
  ]
}

Response:

Status code 200:

The homeserver has processed the notification.

Example

{}

13.2.3   Verifying the invite

When a homeserver receives a m.room.member invite event for a room it's in with a third_party_invite object, it must verify that the association between the third-party identifier initially invited to the room and the Matrix ID that claims to be bound to it has been verified without having to rely on a third-party server.

To do so, it will fetch from the room's state events the m.room.third_party_invite event for which the state key matches with the value for the token key in the third_party_invite object from the m.room.member event's content to fetch the public keys initially delivered by the identity server that stored the invite.

It will then use these keys to verify that the signed object (in the third_party_invite object from the m.room.member event's content) was signed by the same identity server.

Since this signed object can only be delivered once in the POST request emitted by the identity server upon binding between the third-party identifier and the Matrix ID, and contains the invited user's Matrix ID and the token delivered when the invite was stored, this verification will prove that the m.room.member invite event comes from the user owning the invited third-party identifier.

14   Public Room Directory

To complement the Client-Server API's room directory, homeservers need a way to query the public rooms for another server. This can be done by making a request to the /publicRooms endpoint for the server the room directory should be retrieved for.

14.1   GET /_matrix/federation/v1/publicRooms

Gets all the public rooms for the homeserver. This should not return rooms that are listed on another homeserver's directory, just those listed on the receiving homeserver's directory.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
limit integer The maximum number of rooms to return. Defaults to 0 (no limit).
since string A pagination token from a previous call to this endpoint to fetch more rooms.
include_all_networks boolean Whether or not to include all networks/protocols defined by application services on the homeserver. Defaults to false.
third_party_instance_id string The specific third party network/protocol to request from the homeserver. Can only be used if include_all_networks is false.

Response format:

Parameter Type Description
chunk [PublicRoomsChunk] Required. A paginated chunk of public rooms.
next_batch string A pagination token for the response. The absence of this token means there are no more results to fetch and the client should stop paginating.
prev_batch string A pagination token that allows fetching previous results. The absence of this token means there are no results before this batch, i.e. this is the first batch.
total_room_count_estimate integer An estimate on the total number of public rooms, if the server has an estimate.
PublicRoomsChunk
Parameter Type Description
aliases [string] Aliases of the room. May be empty.
canonical_alias string The canonical alias of the room, if any.
name string The name of the room, if any.
num_joined_members integer Required. The number of members joined to the room.
room_id string Required. The ID of the room.
topic string The topic of the room, if any.
world_readable boolean Required. Whether the room may be viewed by guest users without joining.
guest_can_join boolean Required. Whether guest users may join the room and participate in it. If they can, they will be subject to ordinary power level rules like any other user.
avatar_url string The URL for the room's avatar, if one is set.

Example request:

GET /_matrix/federation/v1/publicRooms?limit=10&since=GetMoreRoomsTokenHere&include_all_networks=False&third_party_instance_id=irc HTTP/1.1

Response:

Status code 200:

The public room list for the homeserver.

Example

{
  "chunk": [
    {
      "aliases": [
        "#murrays:cheese.bar"
      ],
      "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE",
      "guest_can_join": false,
      "name": "CHEESE",
      "num_joined_members": 37,
      "room_id": "!ol19s:bleecker.street",
      "topic": "Tasty tasty cheese",
      "world_readable": true
    }
  ],
  "next_batch": "p190q",
  "prev_batch": "p1902",
  "total_room_count_estimate": 115
}

15   Typing Notifications

When a server's users send typing notifications, those notifications need to be sent to other servers in the room so their users are aware of the same state. Receiving servers should verify that the user is in the room, and is a user belonging to the sending server.

15.1   m.typing schema

A typing notification EDU for a user in a room.

m.typing

Parameter Type Description
edu_type enum Required. The string m.typing Must be 'm.typing'.
content Typing Notification Required. The typing notification.

Typing Notification

Parameter Type Description
room_id string Required. The room where the user's typing status has been updated.
user_id string Required. The user ID that has had their typing status changed.
typing boolean Required. Whether the user is typing in the room or not.

Example:

{
    "content": {
        "room_id": "!somewhere:matrix.org",
        "typing": true,
        "user_id": "@john:matrix.org"
    },
    "edu_type": "m.typing"
}

16   Presence

The server API for presence is based entirely on exchange of the following EDUs. There are no PDUs or Federation Queries involved.

Servers should only send presence updates for users that the receiving server would be interested in. This can include the receiving server sharing a room with a given user, or a user on the receiving server has added one of the sending server's users to their presence list.

Clients may define lists of users that they are interested in via "Presence Lists" through the Client-Server API. When users are added to a presence list, a m.presence_invite EDU is sent to them. The user may then accept or deny their involvement in the list by sending either an m.presence_accept or m.presence_deny EDU back.

16.1   m.presence schema

An EDU representing presence updates for users of the sending homeserver.

m.presence

Parameter Type Description
edu_type enum Required. The string m.presence Must be 'm.presence'.
content Presence Update Required. The presence updates and requests.

Presence Update

Parameter Type Description
push [User Presence Update] Required. A list of presence updates that the receiving server is likely to be interested in.

User Presence Update

Parameter Type Description
user_id string Required. The user ID this presence EDU is for.
presence enum Required. The presence of the user. One of: ["offline", "unavailable", "online"]
status_msg string An optional description to accompany the presence.
last_active_ago integer Required. The number of milliseconds that have elapsed since the user last did something.
currently_active boolean True if the user is likely to be interacting with their client. This may be indicated by the user having a last_active_ago within the last few minutes. Defaults to false.

Example:

{
    "content": {
        "push": [
            {
                "currently_active": true,
                "last_active_ago": 5000,
                "presence": "online",
                "status_msg": "Making cupcakes",
                "user_id": "@john:matrix.org"
            }
        ]
    },
    "edu_type": "m.presence"
}

16.2   m.presence_invite schema

An EDU representing a request to subscribe to a user's presence.

m.presence_invite

Parameter Type Description
edu_type enum Required. The string m.presence_invite Must be 'm.presence_invite'.
content Invite Information Required. The invite information.

Invite Information

Parameter Type Description
observed_user string Required. The user ID the observer_user would like to subscribe to the presence of.
observer_user string Required. The user ID that is wishing to subscribe to the presence of the observed_user.

Example:

{
    "content": {
        "observed_user": "@alice:elsewhere.com",
        "observer_user": "@john:matrix.org"
    },
    "edu_type": "m.presence_invite"
}

16.3   m.presence_accept schema

An EDU representing approval for the observing user to subscribe to the presence of the the observed user.

m.presence_accept

Parameter Type Description
edu_type enum Required. The string m.presence_accept Must be 'm.presence_accept'.
content Invite Information Required. The invite information.

Invite Information

Parameter Type Description
observed_user string Required. The user ID that has approved the observer_user to subscribe to their presence.
observer_user string Required. The user ID that requested to subscribe to the presence of the observed_user.

Example:

{
    "content": {
        "observed_user": "@alice:elsewhere.com",
        "observer_user": "@john:matrix.org"
    },
    "edu_type": "m.presence_accept"
}

16.4   m.presence_deny schema

An EDU representing a declination or revocation for the observing user to subscribe to the presence of the observed user.

m.presence_deny

Parameter Type Description
edu_type enum Required. The string m.presence_deny Must be 'm.presence_deny'.
content Invite Information Required. The invite information.

Invite Information

Parameter Type Description
observed_user string Required. The user ID that has declined or revoked the observer_user from subscribing to their presence.
observer_user string Required. The user ID that requested to subscribe to the presence of the observed_user.

Example:

{
    "content": {
        "observed_user": "@alice:elsewhere.com",
        "observer_user": "@john:matrix.org"
    },
    "edu_type": "m.presence_deny"
}

17   Receipts

Receipts are EDUs used to communicate a marker for a given event. Currently the only kind of receipt supported is a "read receipt", or where in the event graph the user has read up to.

Read receipts for events events that a user sent do not need to be sent. It is implied that by sending the event the user has read up to the event.

17.1   m.receipt schema

An EDU representing receipt updates for users of the sending homeserver. When receiving receipts, the server should only update entries that are listed in the EDU. Receipts previously received that do not appear in the EDU should not be removed or otherwise manipulated.

m.receipt

Parameter Type Description
edu_type enum Required. The string m.receipt Must be 'm.receipt'.
content {string: Room Receipts} Required. Receipts for a particular room. The string key is the room ID for which the receipts under it belong.

Room Receipts

Parameter Type Description
m.read User Read Receipt Required. Read receipts for users in the room.

User Read Receipt

Parameter Type Description
event_ids [string] Required. The extremity event IDs that the user has read up to.
data Read Receipt Metadata Required. Metadata for the read receipt.

Read Receipt Metadata

Parameter Type Description
ts integer Required. A POSIX timestamp in milliseconds for when the user read the event specified in the read receipt.

Example:

{
    "content": {
        "!some_room:example.org": {
            "m.read": {
                "@john:matrix.org": {
                    "data": {
                        "ts": 1533358089009
                    },
                    "event_ids": [
                        "$read_this_event:matrix.org"
                    ]
                }
            }
        }
    },
    "edu_type": "m.receipt"
}

18   Querying for information

Queries are a way to retrieve information from a homeserver about a resource, such as a user or room. The endpoints here are often called in conjunction with a request from a client on the client-server API in order to complete the call.

There are several types of queries that can be made. The generic endpoint to represent all queries is described first, followed by the more specific queries that can be made.

18.1   GET /_matrix/federation/v1/query/{queryType}

Performs a single query request on the receiving homeserver. The query string arguments are dependent on which type of query is being made. Known query types are specified as their own endpoints as an extension to this definition.

Requires auth:Yes.

Request format:

Parameter Type Description
path parameters
queryType string Required. The type of query to make

Example request:

GET /_matrix/federation/v1/query/profile HTTP/1.1

Response:

Status code 200:

The query response. The schema varies depending on the query being made.

18.2   GET /_matrix/federation/v1/query/directory

Performs a query to get the mapped room ID and list of resident homeservers in the room for a given room alias. Homeservers should only query room aliases that belong to the target server (identified by the DNS Name in the alias).

Servers may wish to cache the response to this query to avoid requesting the information too often.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
room_alias string Required. The room alias to query.

Response format:

Parameter Type Description
room_id string Required. The room ID mapped to the queried room alias.
servers [string] Required. An array of server names that are likely to hold the given room. This list may or may not include the server answering the query.

Example request:

GET /_matrix/federation/v1/query/directory?room_alias=%23room_alias%3Aexample.org HTTP/1.1

Responses:

Status code 200:

The corresponding room ID and list of known resident homeservers for the room.

Example

{
  "room_id": "!roomid1234:example.org",
  "servers": [
    "example.org",
    "example.com",
    "another.example.com:8449"
  ]
}

Status code 404:

The room alias was not found.

Example

{
  "errcode": "M_NOT_FOUND",
  "error": "Room alias not found."
}

18.3   GET /_matrix/federation/v1/query/profile

Performs a query to get profile information, such as a display name or avatar, for a given user. Homeservers should only query profiles for users that belong to the target server (identified by the DNS Name in the user ID).

Servers may wish to cache the response to this query to avoid requesting the information too often.

Requires auth:Yes.

Request format:

Parameter Type Description
query parameters
user_id string Required. The user ID to query.
field enum The field to query. If specified, the server will only return the given field in the response. If not specified, the server will return the full profile for the user. One of: ["displayname", "avatar_url"]

Response format:

Parameter Type Description
displayname string The display name of the user. May be omitted if the user does not have a display name set.
avatar_url string The avatar URL for the user's avatar. May be omitted if the user does not have an avatar set.

Example request:

GET /_matrix/federation/v1/query/profile?user_id=%40someone%3Aexample.org HTTP/1.1

Responses:

Status code 200:

The profile for the user. If a field is specified in the request, only the matching field should be included in the response. If no field was specified, the response should include the fields of the user's profile that can be made public, such as the display name and avatar.

If the user does not have a particular field set on their profile, the server should exclude it from the response body or give it the value null.

Example

{
  "displayname": "John Doe",
  "avatar_url": "mxc://matrix.org/MyC00lAvatar"
}

Status code 404:

The user does not exist or does not have a profile.

Example

{
  "errcode": "M_NOT_FOUND",
  "error": "User does not exist."
}

19   OpenID

Third party services can exchange an access token previously generated by the Client-Server API for information about a user. This can help verify that a user is who they say they are without granting full access to the user's account.

Access tokens generated by the OpenID API are only good for the OpenID API and nothing else.

19.1   GET /_matrix/federation/v1/openid/userinfo

Exchanges an OpenID access token for information about the user who generated the token. Currently this only exposes the Matrix User ID of the owner.

Request format:

Parameter Type Description
path parameters
access_token string Required. The OpenID access token to get information about the owner for.

Response format:

Parameter Type Description
sub string Required. The Matrix User ID who generated the token.

Example request:

GET /_matrix/federation/v1/openid/userinfo HTTP/1.1

Responses:

Status code 200:

Information about the user who generated the OpenID access token.

Example

{
  "sub": "@alice:example.com"
}

Status code 401:

The token was not recognized or has expired.

Example

{
  "errcode": "M_UNKNOWN_TOKEN",
  "error": "Access token unknown or expired"
}

20   Device Management

Details of a user's devices must be efficiently published to other users and kept up-to-date. This is critical for reliable end-to-end encryption, in order for users to know which devices are participating in a room. It's also required for to-device messaging to work. This section is intended to complement the Device Management module of the Client-Server API.

Matrix currently uses a custom pubsub system for synchronising information about the list of devices for a given user over federation. When a server wishes to determine a remote user's device list for the first time, it should populate a local cache from the result of a /user/keys/query API on the remote server. However, subsequent updates to the cache should be applied by consuming m.device_list_update EDUs. Each new m.device_list_update EDU describes an incremental change to one device for a given user which should replace any existing entry in the local server's cache of that device list. Servers must send m.device_list_update EDUs to all the servers who share a room with a given local user, and must be sent whenever that user's device list changes (i.e. for new or deleted devices, when that user joins a room which contains servers which are not already receiving updates for that user's device list, or changes in device information such as the device's human-readable name).

Servers send m.device_list_update EDUs in a sequence per origin user, each with a unique stream_id. They also include a pointer to the most recent previous EDU(s) that this update is relative to in the prev_id field. To simplify implementation for clustered servers which could send multiple EDUs at the same time, the prev_id field should include all m.device_list_update EDUs which have not been yet been referenced in a EDU. If EDUs are emitted in series by a server, there should only ever be one prev_id in the EDU.

This forms a simple directed acyclic graph of m.device_list_update EDUs, showing which EDUs a server needs to have received in order to apply an update to its local copy of the remote user's device list. If a server receives an EDU which refers to a prev_id it does not recognise, it must resynchronise its list by calling the /user/keys/query API and resume the process. The response contains a stream_id which should be used to correlate with subsequent m.device_list_update EDUs.

20.1   GET /_matrix/federation/v1/user/devices/{userId}

Gets information on all of the user's devices

Requires auth:Yes.

Request format:

Parameter Type Description
path parameters
userId string Required. The user ID to retrieve devices for. Must be a user local to the receiving homeserver.

Response format:

Parameter Type Description
user_id string Required. The user ID devices were requested for.
stream_id integer Required. A unique ID for a given user_id which describes the version of the returned device list. This is matched with the stream_id field in m.device_list_update EDUs in order to incrementally update the returned device_list.
devices [User Device] Required. The user's devices. May be empty.
User Device
Parameter Type Description
device_id string Required. The device ID.
keys DeviceKeys Required. Identity keys for the device.
device_display_name string Optional display name for the device.
DeviceKeys
Parameter Type Description
user_id string Required. The ID of the user the device belongs to. Must match the user ID used when logging in.
device_id string Required. The ID of the device these keys belong to. Must match the device ID used when logging in.
algorithms [string] Required. The encryption algorithms supported by this device.
keys {string: string} Required. Public identity keys. The names of the properties should be in the format <algorithm>:<device_id>. The keys themselves should be encoded as specified by the key algorithm.
signatures {string: {string: string}}

Required. Signatures for the device key object. A map from user ID, to a map from <algorithm>:<device_id> to the signature.

The signature is calculated using the process described at Signing JSON.

Example request:

GET /_matrix/federation/v1/user/devices/%40alice%3Aexample.org HTTP/1.1

Response:

Status code 200:

The user's devices.

Example

{
  "user_id": "@alice:example.org",
  "stream_id": 5,
  "devices": [
    {
      "device_id": "JLAFKJWSCS",
      "keys": {
        "user_id": "@alice:example.com",
        "device_id": "JLAFKJWSCS",
        "algorithms": [
          "m.olm.curve25519-aes-sha256",
          "m.megolm.v1.aes-sha"
        ],
        "keys": {
          "curve25519:JLAFKJWSCS": "3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI",
          "ed25519:JLAFKJWSCS": "lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI"
        },
        "signatures": {
          "@alice:example.com": {
            "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA"
          }
        }
      },
      "device_display_name": "Alice's Mobile Phone"
    }
  ]
}

20.2   m.device_list_update schema

An EDU that lets servers push details to each other when one of their users adds a new device to their account, required for E2E encryption to correctly target the current set of devices for a given user.

m.device_list_update

Parameter Type Description
edu_type enum Required. The string m.device_list_update. Must be 'm.device_list_update'.
content Device List Update Required. The description of the device whose details has changed.

Device List Update

Parameter Type Description
user_id string Required. The user ID who owns this device.
device_id string Required. The ID of the device whose details are changing.
device_display_name string The public human-readable name of this device. Will be absent if the device has no name.
stream_id integer Required. An ID sent by the server for this update, unique for a given user_id. Used to identify any gaps in the sequence of m.device_list_update EDUs broadcast by a server.
prev_id [integer] The stream_ids of any prior m.device_list_update EDUs sent for this user which have not been referred to already in an EDU's prev_id field. If the receiving server does not recognise any of the prev_ids, it means an EDU has been lost and the server should query a snapshot of the device list via /user/keys/query in order to correctly interpret future m.device_list_update EDUs. May be missing or empty for the first EDU in a sequence.
deleted boolean True if the server is announcing that this device has been deleted.
keys DeviceKeys The updated identity keys (if any) for this device. May be absent if the device has no E2E keys defined.

DeviceKeys

Parameter Type Description
user_id string Required. The ID of the user the device belongs to. Must match the user ID used when logging in.
device_id string Required. The ID of the device these keys belong to. Must match the device ID used when logging in.
algorithms [string] Required. The encryption algorithms supported by this device.
keys {string: string} Required. Public identity keys. The names of the properties should be in the format <algorithm>:<device_id>. The keys themselves should be encoded as specified by the key algorithm.
signatures {string: {string: string}}

Required. Signatures for the device key object. A map from user ID, to a map from <algorithm>:<device_id> to the signature.

The signature is calculated using the process described at Signing JSON.

Example:

{
    "content": {
        "deleted": false,
        "device_display_name": "Mobile",
        "device_id": "QBUAZIFURK",
        "keys": {
            "algorithms": [
                "m.olm.curve25519-aes-sha256",
                "m.megolm.v1.aes-sha"
            ],
            "device_id": "JLAFKJWSCS",
            "keys": {
                "curve25519:JLAFKJWSCS": "3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI",
                "ed25519:JLAFKJWSCS": "lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI"
            },
            "signatures": {
                "@alice:example.com": {
                    "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA"
                }
            },
            "user_id": "@alice:example.com"
        },
        "prev_id": [
            5
        ],
        "stream_id": 6,
        "user_id": "@john:example.com"
    },
    "edu_type": "m.device_list_update"
}

21   End-to-End Encryption

This section complements the End-to-End Encryption module of the Client-Server API. For detailed information about end-to-end encryption, please see that module.

The APIs defined here are designed to be able to proxy much of the client's request through to federation, and have the response also be proxied through to the client.

21.1   POST /_matrix/federation/v1/user/keys/claim

Claims one-time keys for use in pre-key messages.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
one_time_keys {string: {string: string}} Required. The keys to be claimed. A map from user ID, to a map from device ID to algorithm name.

Response format:

Parameter Type Description
one_time_keys {string: {string: string or object}} Required. One-time keys for the queried devices. A map from user ID, to a map from devices to a map from <algorithm>:<key_id> to the key object.

Example request:

POST /_matrix/federation/v1/user/keys/claim HTTP/1.1
Content-Type: application/json

{
  "one_time_keys": {
    "@alice:example.com": {
      "JLAFKJWSCS": "signed_curve25519"
    }
  }
}

Response:

Status code 200:

The claimed keys

Example

{
  "one_time_keys": {
    "@alice:example.com": {
      "JLAFKJWSCS": {
        "signed_curve25518:AAAAHg": {
          "key": "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs",
          "signatures": {
            "@alice:example.com": {
              "ed25519:JLAFKJWSCS": "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw"
            }
          }
        }
      }
    }
  }
}

21.2   POST /_matrix/federation/v1/user/keys/query

Returns the current devices and identity keys for the given users.

Requires auth:Yes.

Request format:

Parameter Type Description
JSON body parameters
device_keys {string: [string]} Required. The keys to be downloaded. A map from user ID, to a list of device IDs, or to an empty list to indicate all devices for the corresponding user.

Response format:

Parameter Type Description
device_keys {string: {string: DeviceKeys}} Required. Information on the queried devices. A map from user ID, to a map from device ID to device information. For each device, the information returned will be the same as uploaded via /keys/upload, with the addition of an unsigned property.
DeviceKeys
Parameter Type Description
user_id string Required. The ID of the user the device belongs to. Must match the user ID used when logging in.
device_id string Required. The ID of the device these keys belong to. Must match the device ID used when logging in.
algorithms [string] Required. The encryption algorithms supported by this device.
keys {string: string} Required. Public identity keys. The names of the properties should be in the format <algorithm>:<device_id>. The keys themselves should be encoded as specified by the key algorithm.
signatures {string: {string: string}}

Required. Signatures for the device key object. A map from user ID, to a map from <algorithm>:<device_id> to the signature.

The signature is calculated using the process described at Signing JSON.

unsigned UnsignedDeviceInfo Additional data added to the device key information by intermediate servers, and not covered by the signatures.
UnsignedDeviceInfo
Parameter Type Description
device_display_name string The display name which the user set on the device.

Example request:

POST /_matrix/federation/v1/user/keys/query HTTP/1.1
Content-Type: application/json

{
  "device_keys": {
    "@alice:example.com": []
  }
}

Response:

Status code 200:

The device information.

Example

{
  "device_keys": {
    "@alice:example.com": {
      "JLAFKJWSCS": {
        "user_id": "@alice:example.com",
        "device_id": "JLAFKJWSCS",
        "algorithms": [
          "m.olm.v1.curve25519-aes-sha256",
          "m.megolm.v1.aes-sha"
        ],
        "keys": {
          "curve25519:JLAFKJWSCS": "3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI",
          "ed25519:JLAFKJWSCS": "lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI"
        },
        "signatures": {
          "@alice:example.com": {
            "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA"
          }
        },
        "unsigned": {
          "device_display_name": "Alice's mobile phone"
        }
      }
    }
  }
}

22   Send-to-device messaging

The server API for send-to-device messaging is based on the m.direct_to_device EDU. There are no PDUs or Federation Queries involved.

Each send-to-device message should be sent to the destination server using the following EDU:

22.1   m.direct_to_device schema

An EDU that lets servers push send events directly to a specific device on a remote server - for instance, to maintain an Olm E2E encrypted message channel between a local and remote device.

m.direct_to_device

Parameter Type Description
edu_type enum Required. The string m.direct_to_device. Must be 'm.direct_to_device'.
content To Device Message Required. The description of the direct-to- device message.

To Device Message

Parameter Type Description
sender string Required. User ID of the sender.
type string Required. Event type for the message.
message_id string Required. Unique ID for the message, used for idempotence. Arbitrary utf8 string, of maximum length 32 codepoints.
messages {string: {string: Device Message Contents}} Required. The contents of the messages to be sent. These are arranged in a map of user IDs to a map of device IDs to message bodies. The device ID may also be *, meaning all known devices for the user.

Example:

{
    "content": {
        "message_id": "hiezohf6Hoo7kaev",
        "messages": {
            "alice@example.org": {
                "IWHQUZUIAH": {
                    "algorithm": "m.megolm.v1.aes-sha2",
                    "room_id": "!Cuyf34gef24t:localhost",
                    "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
                    "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8LlfJL7qNBEY..."
                }
            }
        },
        "sender": "john@example.com",
        "type": "m.room_key_request"
    },
    "edu_type": "m.direct_to_device"
}

23   Content Repository

Attachments to events (images, files, etc) are uploaded to a homeserver via the Content Repository described in the Client-Server API. When a server wishes to serve content originating from a remote server, it needs to ask the remote server for the media.

Servers should use the server described in the Matrix Content URI, which has the format mxc://{ServerName}/{MediaID}. Servers should use the download endpoint described in the Client-Server API, being sure to use the allow_remote parameter (set to false).

24   Server Access Control Lists (ACLs)

Server ACLs and their purpose are described in the Server ACLs section of the Client-Server API.

When a remote server makes a request, it MUST be verified to be allowed by the server ACLs. If the server is denied access to a room, the receiving server MUST reply with a 403 HTTP status code and an errcode of M_FORBIDDEN.

The following endpoint prefixes MUST be protected:

  • /_matrix/federation/v1/send (on a per-PDU basis)
  • /_matrix/federation/v1/make_join
  • /_matrix/federation/v1/make_leave
  • /_matrix/federation/v1/send_join
  • /_matrix/federation/v1/send_leave
  • /_matrix/federation/v1/invite
  • /_matrix/federation/v1/state
  • /_matrix/federation/v1/state_ids
  • /_matrix/federation/v1/backfill
  • /_matrix/federation/v1/event_auth
  • /_matrix/federation/v1/query_auth
  • /_matrix/federation/v1/get_missing_events

25   Signing Events

Signing events is complicated by the fact that servers can choose to redact non-essential parts of an event.

25.1   Adding hashes and signatures to outgoing events

Before signing the event, the content hash of the event is calculated as described below. The hash is encoded using Unpadded Base64 and stored in the event object, in a hashes object, under a sha256 key.

The event object is then redacted, following the redaction algorithm. Finally it is signed as described in Signing JSON, using the server's signing key (see also Retrieving server keys).

The signature is then copied back to the original event object.

See Persistent Data Unit schema for an example of a signed event.

25.2   Validating hashes and signatures on received events

When a server receives an event over federation from another server, the receiving server should check the hashes and signatures on that event.

First the signature is checked. The event is redacted following the redaction algorithm, and the resultant object is checked for a signature from the originating server, following the algorithm described in Checking for a signature. Note that this step should succeed whether we have been sent the full event or a redacted copy.

If the signature is found to be valid, the expected content hash is calculated as described below. The content hash in the hashes property of the received event is base64-decoded, and the two are compared for equality.

If the hash check fails, then it is assumed that this is because we have only been given a redacted version of the event. To enforce this, the receiving server should use the redacted copy it calculated rather than the full copy it received.

25.3   Calculating the content hash for an event

The content hash of an event covers the complete event including the unredacted contents. It is calculated as follows.

First, any existing unsigned, signature, and hashes members are removed. The resulting object is then encoded as Canonical JSON, and the JSON is hashed using SHA-256.

25.4   Example code

def hash_and_sign_event(event_object, signing_key, signing_name):
    # First we need to hash the event object.
    content_hash = compute_content_hash(event_object)
    event_object["hashes"] = {"sha256": encode_unpadded_base64(content_hash)}

    # 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_object = strip_non_essential_keys(event_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_object = sign_json(stripped_object, signing_key, signing_name)

    # Copy the signatures from the stripped event to the original event.
    event_object["signatures"] = signed_object["signatures"]

def compute_content_hash(event_object):
    # take a copy of the event before we remove any keys.
    event_object = dict(event_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.
    event_object.pop("unsigned", None)

    # Signatures will depend on the current value of the "hashes" key.
    # We cannot add new hashes without invalidating existing signatures.
    event_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.
    event_object.pop("hashes", None)

    # 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_object)

    return hashlib.sha256(event_json_bytes)