Skip to content
Snippets Groups Projects
specification.rst 95 KiB
Newer Older
  • Learn to ignore specific revisions
  • Matrix Specification
    ====================
    
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    .. WARNING::
    
      The Matrix specification is still very much evolving: the API is not yet frozen
      and this document is in places incomplete, stale, and may contain security
      issues. Needless to say, we have made every effort to highlight the problem
      areas that we're aware of.
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
      We're publishing it at this point because it's complete enough to be more than
      useful and provide a canonical reference to how Matrix is evolving. Our end
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
      goal is to mirror WHATWG's `Living Standard <http://wiki.whatwg.org/wiki/FAQ#What_does_.22Living_Standard.22_mean.3F>`_   
      approach except right now Matrix is more in the process of being born than actually being
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    .. contents:: Table of Contents
    .. sectnum::
    
    
    Matrix is a new set of open APIs for open-federated Instant Messaging and VoIP
    functionality, designed to create and support a new global real-time
    communication ecosystem on the internet. This specification is the ongoing
    result of standardising the APIs used by the various components of the Matrix
    ecosystem to communicate with one another.
    
    The principles that Matrix attempts to follow are:
    
    
    - Pragmatic Web-friendly APIs (i.e. JSON over REST)
    - Keep It Simple & Stupid
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
      + provide a simple architecture with minimal third-party dependencies.
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
      + Fully open federation - anyone should be able to participate in the global
        Matrix network
      + Fully open standard - publicly documented standard with no IP or patent
        licensing encumbrances
      + Fully open source reference implementation - liberally-licensed example
        implementations with no IP or patent licensing encumbrances
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
    - Empowering the end-user
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
      + The user should be able to choose the server and clients they use
      + The user should be control how private their communication is
      + The user should know precisely where their data is stored
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
    - Fully decentralised - no single points of control over conversations or the
      network as a whole
    - Learning from history to avoid repeating it
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    
    
      + Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP
        whilst trying to avoid their failings
    
    
    The functionality that Matrix provides includes:
    
    
    - Creation and management of fully distributed chat rooms with no
      single points of control or failure
    - Eventually-consistent cryptographically secure synchronisation of room
      state across a global open network of federated servers and services
    - Sending and receiving extensible messages in a room with (optional)
      end-to-end encryption
    - Extensible user management (inviting, joining, leaving, kicking, banning)
      mediated by a power-level based user privilege system.
    - Extensible room state management (room naming, aliasing, topics, bans)
    - Extensible user profile management (avatars, displaynames, etc)
    - Managing user accounts (registration, login, logout)
    - Use of 3rd Party IDs (3PIDs) such as email addresses, phone numbers,
      Facebook accounts to authenticate, identify and discover users on Matrix.
    - Trusted federation of Identity servers for:
    
      + Publishing user public keys for PKI
      + Mapping of 3PIDs to Matrix IDs
    
    
    The end goal of Matrix is to be a ubiquitous messaging layer for synchronising
    
    arbitrary data between sets of people, devices and services - be that for
    instant messages, VoIP call setups, or any other objects that need to be
    reliably and persistently pushed from A to B in an interoperable and federated
    manner.
    
    ------------
    
    Clients transmit data to other clients through home servers (HSes). Clients do
    not communicate with each other directly.
    
                             How data flows between clients
                             ==============================
    
           { Matrix client A }                             { Matrix client B }
    
               ^          |                                    ^          |
               |  events  |                                    |  events  |
               |          V                                    |          V
           +------------------+                            +------------------+
           |                  |---------( HTTP )---------->|                  |
           |   Home Server    |                            |   Home Server    |
           |                  |<--------( HTTP )-----------|                  |
    
           +------------------+        Federation          +------------------+
    
    
    A "Client" typically represents a human using a web application or mobile app.
    Clients use the "Client-to-Server" (C-S) API to communicate with their home
    server, which stores their profile data and their record of the conversations
    in which they participate. Each client is associated with a user account (and
    may optionally support multiple user accounts). A user account is represented
    by a unique "User ID". This ID is namespaced to the home server which allocated
    the account and looks like::
    
    The ``localpart`` of a user ID may be a user name, or an opaque ID identifying
    this user. They are case-insensitive.
    
        - Need to specify precise grammar for Matrix IDs
    
    
    A "Home Server" is a server which provides C-S APIs and has the ability to
    federate with other HSes.  It is typically responsible for multiple clients.
    "Federation" is the term used to describe the sharing of data between two or
    more home servers.
    
    Data in Matrix is encapsulated in an "event". An event is an action within the
    system. Typically each action (e.g. sending a message) correlates with exactly
    one event. Each event has a ``type`` which is used to differentiate different
    kinds of data. ``type`` values MUST be uniquely globally namespaced following
    Java's `package naming conventions
    <http://docs.oracle.com/javase/specs/jls/se5.0/html/packages.html#7.7>`, e.g.
    ``com.example.myapp.event``. The special top-level namespace ``m.`` is reserved
    for events defined in the Matrix specification. Events are usually sent in the
    context of a "Room".
    
    ~~~~~~~~~~~~~~
    
    A room is a conceptual place where users can send and receive events. Rooms can
    be created, joined and left. Events are sent to a room, and all participants in
    that room with sufficient access will receive the event. Rooms are uniquely
    
    identified internally via a "Room ID", which look like::
    
    There is exactly one room ID for each room. Whilst the room ID does contain a
    
    domain, it is simply for globally namespacing room IDs. The room does NOT
    reside on the domain specified. Room IDs are not meant to be human readable.
    They ARE case-sensitive.
    
    The following diagram shows an ``m.room.message`` event being sent in the room 
    ``!qporfwt:matrix.org``::
    
    
           { @alice:matrix.org }                             { @bob:domain.com }
                   |                                                 ^
                   |                                                 |
          Room ID: !qporfwt:matrix.org                 Room ID: !qporfwt:matrix.org
          Event type: m.room.message                   Event type: m.room.message
          Content: { JSON object }                     Content: { JSON object }
                   |                                                 |
                   V                                                 |
    
           +------------------+                          +------------------+
           |   Home Server    |                          |   Home Server    |
           |   matrix.org     |<-------Federation------->|   domain.com     |
           +------------------+                          +------------------+
                    |       .................................        |
    
                    |______|           Shared State          |_______|
    
                           | Servers: matrix.org, domain.com |
                           | Members:                        |
                           |  - @alice:matrix.org            |
                           |  - @bob:domain.com              |
                           |.................................|
    
    
    Federation maintains shared state between multiple home servers, such that when
    an event is sent to a room, the home server knows where to forward the event on
    
    to, and how to process the event. State is scoped to a single room, and
    federation ensures that all home servers have the information they need, even
    if that means the home server has to request more information from another home
    server before processing the event.
    
    ~~~~~~~~~~~~
    
    
    Each room can also have multiple "Room Aliases", which looks like::
    
      #room_alias:domain
    
    
          - Need to specify precise grammar for Room Aliases
    
    A room alias "points" to a room ID and is the human-readable label by which
    rooms are publicised and discovered.  The room ID the alias is pointing to can
    be obtained by visiting the domain specified. They are case-insensitive. Note
    that the mapping from a room alias to a room ID is not fixed, and may change
    over time to point to a different room ID. For this reason, Clients SHOULD
    resolve the room alias to a room ID once and then use that ID on subsequent
    requests.
    
    When resolving a room alias the server will also respond with a list of servers
    that are in the room that can be used to join via.
    
    
    ::
    
              GET    
       #matrix:domain.com      !aaabaa:matrix.org
               |                    ^
               |                    |
        _______V____________________|____
       |          domain.com            |
       | Mappings:                      |
       | #matrix >> !aaabaa:matrix.org  |
    
       | #golf   >> !wfeiofh:sport.com  |
       | #bike   >> !4rguxf:matrix.org  |
    
    Users in Matrix are identified via their user ID. However, existing ID
    namespaces can also be used in order to identify Matrix users. A Matrix
    "Identity" describes both the user ID and any other existing IDs from third
    party namespaces *linked* to their account.
    
    
    Matrix users can *link* third-party IDs (3PIDs) such as email addresses, social
    
    network accounts and phone numbers to their user ID. Linking 3PIDs creates a
    mapping from a 3PID to a user ID. This mapping can then be used by other Matrix
    users in order to discover other users, according to a strict set of privacy
    permissions.
    
    In order to ensure that the mapping from 3PID to user ID is genuine, a globally
    federated cluster of trusted "Identity Servers" (IS) are used to perform
    authentication of the 3PID.  Identity servers are also used to preserve the
    mapping indefinitely, by replicating the mappings across multiple ISes.
    
    Usage of an IS is not required in order for a client application to be part of
    
    the Matrix ecosystem. However, without one clients will not be able to look up
    user IDs using 3PIDs.
    
    Presence
    ~~~~~~~~
    .. NOTE::
      This section is a work in progress.
    
    Each user has the concept of presence information. This encodes the
    "availability" of that user, suitable for display on other user's clients. This
    is transmitted as an ``m.presence`` event and is one of the few events which
    are sent *outside the context of a room*. The basic piece of presence
    information is represented by the ``presence`` key, which is an enum of one of
    the following:
    
      - ``online`` : The default state when the user is connected to an event
        stream.
      - ``unavailable`` : The user is not reachable at this time.
      - ``offline`` : The user is not connected to an event stream.
      - ``free_for_chat`` : The user is generally willing to receive messages
        moreso than default.
      - ``hidden`` : Behaves as offline, but allows the user to see the client
        state anyway and generally interact with client features. (Not yet
        implemented in synapse).
    
    This basic ``presence`` field applies to the user as a whole, regardless of how
    many client devices they have connected. The home server should synchronise
    this status choice among multiple devices to ensure the user gets a consistent
    experience.
    
    In addition, the server maintains a timestamp of the last time it saw an active
    action from the user; either sending a message to a room, or changing presence
    state from a lower to a higher level of availability (thus: changing state from
    ``unavailable`` to ``online`` will count as an action for being active, whereas
    in the other direction will not). This timestamp is presented via a key called
    ``last_active_ago``, which gives the relative number of miliseconds since the
    message is generated/emitted, that the user was last seen active.
    
    Home servers can also use the user's choice of presence state as a signal for
    how to handle new private one-to-one chat message requests. For example, it
    might decide:
    
      - ``free_for_chat`` : accept anything
      - ``online`` : accept from anyone in my addres book list
      - ``busy`` : accept from anyone in this "important people" group in my
        address book list
    
    Presence List
    +++++++++++++
    Each user's home server stores a "presence list" for that user. This stores a
    list of other user IDs the user has chosen to add to it. To be added to this
    list, the user being added must receive permission from the list owner. Once
    granted, both user's HS(es) store this information. Since such subscriptions
    are likely to be bidirectional, HSes may wish to automatically accept requests
    when a reverse subscription already exists.
    
    As a convenience, presence lists should support the ability to collect users
    into groups, which could allow things like inviting the entire group to a new
    ("ad-hoc") chat room, or easy interaction with the profile information ACL
    implementation of the HS.
    
    Presence and Permissions
    ++++++++++++++++++++++++
    For a viewing user to be allowed to see the presence information of a target
    user, either:
    
     - The target user has allowed the viewing user to add them to their presence
       list, or
     - The two users share at least one room in common
    
    In the latter case, this allows for clients to display some minimal sense of
    presence information in a user list for a room.
    
    Profiles
    ~~~~~~~~
    .. NOTE::
      This section is a work in progress.
    
    .. TODO-spec
      - Metadata extensibility
    
    Internally within Matrix users are referred to by their user ID, which is
    typically a compact unique identifier. Profiles grant users the ability to see
    human-readable names for other users that are in some way meaningful to them.
    Additionally, profiles can publish additional information, such as the user's
    age or location.
    
    A Profile consists of a display name, an avatar picture, and a set of other
    metadata fields that the user may wish to publish (email address, phone
    numbers, website URLs, etc...). This specification puts no requirements on the
    display name other than it being a valid unicode string. Avatar images are not
    stored directly; instead the home server stores an ``http``-scheme URL where
    clients may fetch it from.
    
    
    The mandatory baseline for communication in Matrix is exchanging JSON objects
    over RESTful HTTP APIs. HTTPS is mandated as the baseline for server-server
    (federation) communication.  HTTPS is recommended for client-server
    communication, although HTTP may be supported as a fallback to support basic
    HTTP clients. More efficient optional transports for client-server
    communication will in future be supported as optional extensions - e.g. a
    
    packed binary encoding over stream-cipher encrypted TCP socket for
    low-bandwidth/low-roundtrip mobile usage.
    
    .. TODO
      We need to specify capability negotiation for extensible transports
    
    
    For the default HTTP transport, all API calls use a Content-Type of
    ``application/json``.  In addition, all strings MUST be encoded as UTF-8.
    
    Clients are authenticated using opaque ``access_token`` strings (see
    
    `Registration and Login`_ for details), passed as a query string parameter on
    
    
    .. TODO
      Need to specify any HMAC or access_token lifetime/ratcheting tricks
    
    
    Any errors which occur on the Matrix API level MUST return a "standard error
    response". This is a JSON object which looks like::
    
    Kegan Dougal's avatar
    Kegan Dougal committed
    
      {
        "errcode": "<error code>",
        "error": "<error message>"
      }
    
    The ``error`` string will be a human-readable error message, usually a sentence
    
    explaining what went wrong. The ``errcode`` string will be a unique string
    which can be used to handle an error message e.g. ``M_FORBIDDEN``. These error
    codes should have their namespace first in ALL CAPS, followed by a single _.
    For example, if there was a custom namespace ``com.mydomain.here``, and a
    ``FORBIDDEN`` code, the error code should look like
    ``COM.MYDOMAIN.HERE_FORBIDDEN``. There may be additional keys depending on the
    error, but the keys ``error`` and ``errcode`` MUST always be present. 
    
    Kegan Dougal's avatar
    Kegan Dougal committed
    
    Some standard error codes are below:
    
    :``M_FORBIDDEN``:
      Forbidden access, e.g. joining a room without permission, failed login.
    
    :``M_UNKNOWN_TOKEN``:
      The access token specified was not recognised.
    
    :``M_BAD_JSON``:
      Request contained valid JSON, but it was malformed in some way, e.g. missing
      required keys, invalid values for keys.
    
    :``M_NOT_JSON``:
      Request did not contain valid JSON.
    
    :``M_NOT_FOUND``:
      No resource was found for this request.
    
    
    :``M_LIMIT_EXCEEDED``:
      Too many requests have been sent in a short period of time. Wait a while then
      try again.
    
    
    Kegan Dougal's avatar
    Kegan Dougal committed
    Some requests have unique error codes:
    
    :``M_USER_IN_USE``:
      Encountered when trying to register a user ID which has been taken.
    
    :``M_ROOM_IN_USE``:
      Encountered when trying to create a room which has been taken.
    
    :``M_BAD_PAGINATION``:
      Encountered when specifying bad pagination query parameters.
    
    :``M_LOGIN_EMAIL_URL_NOT_YET``:
      Encountered when polling for an email link which has not been clicked yet.
    
    
    The C-S API typically uses ``HTTP POST`` to submit requests. This means these
    requests are not idempotent. The C-S API also allows ``HTTP PUT`` to make
    requests idempotent. In order to use a ``PUT``, paths should be suffixed with
    ``/{txnId}``. ``{txnId}`` is a unique client-generated transaction ID which
    identifies the request, and is scoped to a given Client (identified by that
    client's ``access_token``). Crucially, it **only** serves to identify new
    requests from retransmits. After the request has finished, the ``{txnId}``
    value should be changed (how is not specified; a monotonically increasing
    integer is recommended). It is preferable to use ``HTTP PUT`` to make sure
    requests to send messages do not get sent more than once should clients need to
    retransmit requests.
    
    Kegan Dougal's avatar
    Kegan Dougal committed
    
    Valid requests look like::
    
    
        POST /some/path/here?access_token=secret
    
    Kegan Dougal's avatar
    Kegan Dougal committed
        {
          "key": "This is a post."
        }
    
    
        PUT /some/path/here/11?access_token=secret
    
    Kegan Dougal's avatar
    Kegan Dougal committed
        {
          "key": "This is a put with a txnId of 11."
        }
    
    In contrast, these are invalid requests::
    
    
        POST /some/path/here/11?access_token=secret
    
    Kegan Dougal's avatar
    Kegan Dougal committed
        {
          "key": "This is a post, but it has a txnId."
        }
    
    
        PUT /some/path/here?access_token=secret
    
    Kegan Dougal's avatar
    Kegan Dougal committed
        {
          "key": "This is a put but it is missing a txnId."
        }
    
    Glossary
    --------
    .. NOTE::
      This section is a work in progress.
    
    Backfilling:
      The process of synchronising historic state from one home server to another,
      to backfill the event storage so that scrollback can be presented to the
      client(s). Not to be confused with pagination.
    
    Context:
      A single human-level entity of interest (currently, a chat room)
    
    EDU (Ephemeral Data Unit):
      A message that relates directly to a given pair of home servers that are
      exchanging it. EDUs are short-lived messages that related only to one single
      pair of servers; they are not persisted for a long time and are not forwarded
      on to other servers. Because of this, they have no internal ID nor previous
      EDUs reference chain.
    
    Event:
      A record of activity that records a single thing that happened on to a context
      (currently, a chat room). These are the "chat messages" that Synapse makes
      available.
    
    PDU (Persistent Data Unit):
      A message that relates to a single context, irrespective of the server that
      is communicating it. PDUs either encode a single Event, or a single State
      change. A PDU is referred to by its PDU ID; the pair of its origin server
      and local reference from that server.
    
    PDU ID:
      The pair of PDU Origin and PDU Reference, that together globally uniquely
      refers to a specific PDU.
    
    PDU Origin:
      The name of the origin server that generated a given PDU. This may not be the
      server from which it has been received, due to the way they are copied around
      from server to server. The origin always records the original server that
      created it.
    
    PDU Reference:
      A local ID used to refer to a specific PDU from a given origin server. These
      references are opaque at the protocol level, but may optionally have some
      structured meaning within a given origin server or implementation.
    
    Presence:
      The concept of whether a user is currently online, how available they declare
      they are, and so on. See also: doc/model/presence
    
    Profile:
      A set of metadata about a user, such as a display name, provided for the
      benefit of other users. See also: doc/model/profiles
    
    Room ID:
      An opaque string (of as-yet undecided format) that identifies a particular
      room and used in PDUs referring to it.
    
    Room Alias:
      A human-readable string of the form #name:some.domain that users can use as a
      pointer to identify a room; a Directory Server will map this to its Room ID
    
    State:
      A set of metadata maintained about a Context, which is replicated among the
      servers in addition to the history of Events.
    
    User ID:
      A string of the form @localpart:domain.name that identifies a user for
      wire-protocol purposes. The localpart is meaningless outside of a particular
      home server. This takes a human-readable form that end-users can use directly
      if they so wish, avoiding the 3PIDs.
    
    Transaction:
      A message which relates to the communication between a given pair of servers.
      A transaction contains possibly-empty lists of PDUs and EDUs.
    
    .. TODO
      This glossary contradicts the terms used above - especially on State Events v. "State"
      and Non-State Events v. "Events".  We need better consistent names.
    
    Events
    ======
    
    
    Receiving live updates on a client
    ----------------------------------
    
    Clients can receive new events by long-polling the home server. This will hold
    open the HTTP connection for a short period of time waiting for new events,
    returning early if an event occurs. This is called the `Event Stream`_. All
    events which are visible to the client will appear in the event stream. When
    the request returns, an ``end`` token is included in the response. This token
    can be used in the next request to continue where the client left off.
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
      How do we filter the event stream?
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
      Do we ever return multiple events in a single request?  Don't we get lots of request
      setup RTT latency if we only do one event per request? Do we ever support streaming
    
      requests? Why not websockets?
    
    When the client first logs in, they will need to initially synchronise with
    their home server. This is achieved via the |initialSync|_ API. This API also
    returns an ``end`` token which can be used with the event stream.
    
    Room Events
    -----------
    .. NOTE::
      This section is a work in progress.
    
    This specification outlines several standard event types, all of which are
    prefixed with ``m.``
    
    ``m.room.name``
      Summary:
        Set the human-readable name for the room.
      Type: 
        State event
      JSON format:
        ``{ "name" : "string" }``
      Example:
        ``{ "name" : "My Room" }``
      Description:
        A room has an opaque room ID which is not human-friendly to read. A room
        alias is human-friendly, but not all rooms have room aliases. The room name
        is a human-friendly string designed to be displayed to the end-user. The
        room name is not *unique*, as multiple rooms can have the same room name
        set. The room name can also be set when creating a room using |createRoom|_
        with the ``name`` key.
    
    ``m.room.topic``
      Summary:
        Set a topic for the room.
      Type: 
        State event
      JSON format:
        ``{ "topic" : "string" }``
      Example:
        ``{ "topic" : "Welcome to the real world." }``
      Description:
        A topic is a short message detailing what is currently being discussed in
        the room.  It can also be used as a way to display extra information about
        the room, which may not be suitable for the room name. The room topic can
        also be set when creating a room using |createRoom|_ with the ``topic``
        key.
    
    ``m.room.member``
      Summary:
        The current membership state of a user in the room.
      Type: 
        State event
      JSON format:
        ``{ "membership" : "enum[ invite|join|leave|ban ]" }``
      Example:
        ``{ "membership" : "join" }``
      Description:
        Adjusts the membership state for a user in a room. It is preferable to use
        the membership APIs (``/rooms/<room id>/invite`` etc) when performing
        membership actions rather than adjusting the state directly as there are a
        restricted set of valid transformations. For example, user A cannot force
        user B to join a room, and trying to force this state change directly will
        fail. See the `Rooms`_ section for how to use the membership APIs.
    
    ``m.room.create``
      Summary:
        The first event in the room.
      Type: 
        State event
      JSON format:
        ``{ "creator": "string"}``
      Example:
        ``{ "creator": "@user:example.com" }``
      Description:
        This is the first event in a room and cannot be changed. It acts as the 
        root of all other events.
    
    ``m.room.join_rules``
      Summary:
        Descripes how/if people are allowed to join.
      Type: 
        State event
      JSON format:
        ``{ "join_rule": "enum [ public|knock|invite|private ]" }``
      Example:
        ``{ "join_rule": "public" }``
      Description:
        TODO-doc : Use docs/models/rooms.rst
       
    ``m.room.power_levels``
      Summary:
        Defines the power levels of users in the room.
      Type: 
        State event
      JSON format:
        ``{ "<user_id>": <int>, ..., "default": <int>}``
      Example:
        ``{ "@user:example.com": 5, "@user2:example.com": 10, "default": 0 }`` 
      Description:
        If a user is in the list, then they have the associated power level. 
        Otherwise they have the default level. If not ``default`` key is supplied,
        it is assumed to be 0.
    
    ``m.room.add_state_level``
      Summary:
        Defines the minimum power level a user needs to add state.
      Type: 
        State event
      JSON format:
        ``{ "level": <int> }``
      Example:
        ``{ "level": 5 }``
      Description:
        To add a new piece of state to the room a user must have the given power 
        level. This does not apply to updating current state, which is goverened
        by the ``required_power_level`` event key.
    
    ``m.room.send_event_level``
      Summary:
        Defines the minimum power level a user needs to send an event.
      Type: 
        State event
      JSON format:
        ``{ "level": <int> }``
      Example:
        ``{ "level": 0 }``
      Description:
        To send a new event into the room a user must have at least this power 
        level. This allows ops to make the room read only by increasing this level,
        or muting individual users by lowering their power level below this
        threshold.
    
    ``m.room.ops_levels``
      Summary:
        Defines the minimum power levels that a user must have before they can 
        kick and/or ban other users.
      Type: 
        State event
      JSON format:
        ``{ "ban_level": <int>, "kick_level": <int>, "redact_level": <int> }``
      Example:
        ``{ "ban_level": 5, "kick_level": 5 }``
      Description:
        This defines who can ban and/or kick people in the room. Most of the time
        ``ban_level`` will be greater than or equal to ``kick_level`` since 
        banning is more severe than kicking.
    
    ``m.room.aliases``
      Summary:
        These state events are used to inform the room about what room aliases it
        has.
      Type:
        State event
      JSON format:
        ``{ "aliases": ["string", ...] }``
      Example:
        ``{ "aliases": ["#foo:example.com"] }``
      Description:
        This event is sent by a homeserver directly to inform of changes to the
        list of aliases it knows about for that room. As a special-case, the
        ``state_key`` of the event is the homeserver which owns the room alias.
        For example, an event might look like::
    
          {
            "type": "m.room.aliases",
            "event_id": "012345678ab",
            "room_id": "!xAbCdEfG:example.com",
            "state_key": "example.com",
            "content": {
              "aliases": ["#foo:example.com"]
            }
          }
    
        The event contains the full list of aliases now stored by the home server
        that emitted it; additions or deletions are not explicitly mentioned as
        being such. The entire set of known aliases for the room is then the union
        of the individual lists declared by all such keys, one from each home
        server holding at least one alias.
    
        Clients `should` check the validity of any room alias given in this list
        before presenting it to the user as trusted fact. The lists given by this
        event should be considered simply as advice on which aliases might exist,
        for which the client can perform the lookup to confirm whether it receives
        the correct room ID.
    
    ``m.room.message``
      Summary:
        A message.
      Type: 
        Non-state event
      JSON format:
        ``{ "msgtype": "string" }``
      Example:
        ``{ "msgtype": "m.text", "body": "Testing" }``
      Description:
        This event is used when sending messages in a room. Messages are not
        limited to be text.  The ``msgtype`` key outlines the type of message, e.g.
        text, audio, image, video, etc.  Whilst not required, the ``body`` key
        SHOULD be used with every kind of ``msgtype`` as a fallback mechanism when
        a client cannot render the message. For more information on the types of
        messages which can be sent, see `m.room.message msgtypes`_.
    
    ``m.room.message.feedback``
      Summary:
        A receipt for a message.
      Type: 
        Non-state event
      JSON format:
        ``{ "type": "enum [ delivered|read ]", "target_event_id": "string" }``
      Example:
        ``{ "type": "delivered", "target_event_id": "e3b2icys" }``
      Description:
        Feedback events are events sent to acknowledge a message in some way. There
        are two supported acknowledgements: ``delivered`` (sent when the event has
        been received) and ``read`` (sent when the event has been observed by the
        end-user). The ``target_event_id`` should reference the ``m.room.message``
        event being acknowledged. 
    
    ``m.room.redaction``
      Summary:
        Indicates a previous event has been redacted.
      Type:
        Non-state event
      JSON format:
        ``{ "reason": "string" }``
      Description:
        Events can be redacted by either room or server admins. Redacting an event
        means that all keys not required by the protocol are stripped off, allowing
        admins to remove offensive or illegal content that may have been attached
        to any event. This cannot be undone, allowing server owners to physically
        delete the offending data.  There is also a concept of a moderator hiding a
        non-state event, which can be undone, but cannot be applied to state
        events.
        The event that has been redacted is specified in the ``redacts`` event
        level key.
    
    m.room.message msgtypes
    ~~~~~~~~~~~~~~~~~~~~~~~
    
    .. TODO-spec
       How a client should handle unknown message types.
    
    Each ``m.room.message`` MUST have a ``msgtype`` key which identifies the type
    of message being sent. Each type has their own required and optional keys, as
    outlined below:
    
    ``m.text``
      Required keys:
        - ``body`` : "string" - The body of the message.
      Optional keys:
        None.
      Example:
        ``{ "msgtype": "m.text", "body": "I am a fish" }``
    
    ``m.emote``
      Required keys:
        - ``body`` : "string" - The emote action to perform.
      Optional keys:
        None.
      Example:
        ``{ "msgtype": "m.emote", "body": "tries to come up with a witty explanation" }``
    
    ``m.image``
      Required keys:
        - ``url`` : "string" - The URL to the image.
      Optional keys:
        - ``info`` : "string" - info : JSON object (ImageInfo) - The image info for
          image referred to in ``url``.
        - ``thumbnail_url`` : "string" - The URL to the thumbnail.
        - ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
          image referred to in ``thumbnail_url``.
        - ``body`` : "string" - The alt text of the image, or some kind of content
          description for accessibility e.g. "image attachment".
    
      ImageInfo: 
        Information about an image::
        
          { 
            "size" : integer (size of image in bytes),
            "w" : integer (width of image in pixels),
            "h" : integer (height of image in pixels),
            "mimetype" : "string (e.g. image/jpeg)",
          }
    
    ``m.audio``
      Required keys:
        - ``url`` : "string" - The URL to the audio.
      Optional keys:
        - ``info`` : JSON object (AudioInfo) - The audio info for the audio
          referred to in ``url``.
        - ``body`` : "string" - A description of the audio e.g. "Bee Gees - Stayin'
          Alive", or some kind of content description for accessibility e.g.
          "audio attachment".
      AudioInfo: 
        Information about a piece of audio::
    
            "mimetype" : "string (e.g. audio/aac)",
            "size" : integer (size of audio in bytes),
            "duration" : integer (duration of audio in milliseconds),
    
    ``m.video``
      Required keys:
        - ``url`` : "string" - The URL to the video.
      Optional keys:
        - ``info`` : JSON object (VideoInfo) - The video info for the video
          referred to in ``url``.
        - ``body`` : "string" - A description of the video e.g. "Gangnam style", or
          some kind of content description for accessibility e.g. "video
          attachment".
    
      VideoInfo: 
        Information about a video::
    
          {
            "mimetype" : "string (e.g. video/mp4)",
            "size" : integer (size of video in bytes),
            "duration" : integer (duration of video in milliseconds),
            "w" : integer (width of video in pixels),
            "h" : integer (height of video in pixels),
            "thumbnail_url" : "string (URL to image)",
            "thumbanil_info" : JSON object (ImageInfo)
          }
    
    ``m.location``
      Required keys:
        - ``geo_uri`` : "string" - The geo URI representing the location.
      Optional keys:
        - ``thumbnail_url`` : "string" - The URL to a thumnail of the location
          being represented.
        - ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
          image referred to in ``thumbnail_url``.
        - ``body`` : "string" - A description of the location e.g. "Big Ben,
          London, UK", or some kind of content description for accessibility e.g.
          "location attachment".
    
    The following keys can be attached to any ``m.room.message``:
    
      Optional keys:
        - ``sender_ts`` : integer - A timestamp (ms resolution) representing the
          wall-clock time when the message was sent from the client.
    
    Events on Change of Profile Information
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Because the profile displayname and avatar information are likely to be used in
    many places of a client's display, changes to these fields cause an automatic
    propagation event to occur, informing likely-interested parties of the new
    values. This change is conveyed using two separate mechanisms:
    
     - a ``m.room.member`` event is sent to every room the user is a member of,
       to update the ``displayname`` and ``avatar_url``.
     - a presence status update is sent, again containing the new values of the
       ``displayname`` and ``avatar_url`` keys, in addition to the required
       ``presence`` key containing the current presence state of the user.
    
    Both of these should be done automatically by the home server when a user
    successfully changes their displayname or avatar URL fields.
    
    Additionally, when home servers emit room membership events for their own
    users, they should include the displayname and avatar URL fields in these
    events so that clients already have these details to hand, and do not have to
    perform extra roundtrips to query it.
    
    Voice over IP
    -------------
    Matrix can also be used to set up VoIP calls. This is part of the core
    specification, although is still in a very early stage. Voice (and video) over
    Matrix is based on the WebRTC standards.
    
    Call events are sent to a room, like any other event. This means that clients
    must only send call events to rooms with exactly two participants as currently
    the WebRTC standard is based around two-party communication.
    
    Events
    ~~~~~~
    ``m.call.invite``
    This event is sent by the caller when they wish to establish a call.
    
      Required keys:
        - ``call_id`` : "string" - A unique identifier for the call
        - ``offer`` : "offer object" - The session description
        - ``version`` : "integer" - The version of the VoIP specification this
          message adheres to. This specification is version 0.
        - ``lifetime`` : "integer" - The time in milliseconds that the invite is
          valid for. Once the invite age exceeds this value, clients should discard
          it. They should also no longer show the call as awaiting an answer in the
          UI.
          
      Optional keys:
        None.
      Example:
        ``{ "version" : 0, "call_id": "12345", "offer": { "type" : "offer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" } }``
    
    ``Offer Object``
      Required keys:
        - ``type`` : "string" - The type of session description, in this case
          'offer'
        - ``sdp`` : "string" - The SDP text of the session description
    
    ``m.call.candidates``
    This event is sent by callers after sending an invite and by the callee after
    answering.  Its purpose is to give the other party additional ICE candidates to
    try using to communicate.
    
      Required keys:
        - ``call_id`` : "string" - The ID of the call this event relates to
        - ``version`` : "integer" - The version of the VoIP specification this
          messages adheres to. his specification is version 0.
        - ``candidates`` : "array of candidate objects" - Array of object
          describing the candidates.
    
    ``Candidate Object``
    
      Required Keys:
        - ``sdpMid`` : "string" - The SDP media type this candidate is intended
          for.
        - ``sdpMLineIndex`` : "integer" - The index of the SDP 'm' line this
          candidate is intended for
        - ``candidate`` : "string" - The SDP 'a' line of the candidate
    
    ``m.call.answer``
    
      Required keys:
        - ``call_id`` : "string" - The ID of the call this event relates to
        - ``version`` : "integer" - The version of the VoIP specification this
          messages
        - ``answer`` : "answer object" - Object giving the SDK answer
    
    ``Answer Object``
    
      Required keys:
        - ``type`` : "string" - The type of session description. 'answer' in this
          case.
        - ``sdp`` : "string" - The SDP text of the session description
    
    ``m.call.hangup``
    Sent by either party to signal their termination of the call. This can be sent
    either once the call has has been established or before to abort the call.
    
      Required keys:
        - ``call_id`` : "string" - The ID of the call this event relates to
        - ``version`` : "integer" - The version of the VoIP specification this
          messages
    
    Message Exchange
    ~~~~~~~~~~~~~~~~
    A call is set up with messages exchanged as follows:
    
       Caller                   Callee
     m.call.invite ----------->
     m.call.candidate -------->
     [more candidates events]
                             User answers call
                      <------ m.call.answer