diff --git a/docs/specification.rst b/docs/specification.rst
index 3686ea8366a5db91d69fa0b085ca42885f5e177d..e2626078a1568fbe89232b32b10809099bdcbf9d 100644
--- a/docs/specification.rst
+++ b/docs/specification.rst
@@ -260,7 +260,7 @@ 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 querystring parameter on
+`Registration and Login`_ for details), passed as a query string parameter on
 all requests.
 
 .. TODO
@@ -375,1291 +375,1292 @@ 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.
 
-Rooms
-=====
-
-Creation
---------
-.. TODO kegan
-  - TODO: Key for invite these users?
-  
-To create a room, a client has to use the |createRoom|_ API. There are various
-options which can be set when creating a room:
-
-``visibility``
-  Type: 
-    String
-  Optional: 
-    Yes
-  Value:
-    Either ``public`` or ``private``.
-  Description:
-    A ``public`` visibility indicates that the room will be shown in the public
-    room list. A ``private`` visibility will hide the room from the public room
-    list. Rooms default to ``public`` visibility if this key is not included.
 
-``room_alias_name``
-  Type: 
-    String
-  Optional: 
-    Yes
-  Value:
-    The room alias localpart.
-  Description:
-    If this is included, a room alias will be created and mapped to the newly
-    created room.  The alias will belong on the same home server which created
-    the room, e.g.  ``!qadnasoi:domain.com >>> #room_alias_name:domain.com``
+Registration and login
+======================
 
-``name``
-  Type: 
-    String
-  Optional: 
-    Yes
-  Value:
-    The ``name`` value for the ``m.room.name`` state event.
-  Description:
-    If this is included, an ``m.room.name`` event will be sent into the room to
-    indicate the name of the room. See `Room Events`_ for more information on
-    ``m.room.name``.
+Clients must register with a home server in order to use Matrix. After
+registering, the client will be given an access token which must be used in ALL
+requests to that home server as a query parameter 'access_token'.
 
-``topic``
-  Type: 
-    String
-  Optional: 
-    Yes
-  Value:
-    The ``topic`` value for the ``m.room.topic`` state event.
-  Description:
-    If this is included, an ``m.room.topic`` event will be sent into the room
-    to indicate the topic for the room. See `Room Events`_ for more information
-    on ``m.room.topic``.
+If the client has already registered, they need to be able to login to their
+account. The home server may provide many different ways of logging in, such as
+user/password auth, login via a social network (OAuth2), login by confirming a
+token sent to their email address, etc. This specification does not define how
+home servers should authorise their users who want to login to their existing
+accounts, but instead defines the standard interface which implementations
+should follow so that ANY client can login to ANY home server. Clients login
+using the |login|_ API. Clients register using the |register|_ API.
+Registration follows the same procedure as login, but the path requests are
+sent to are different.
 
-``invite``
-  Type:
-    List
-  Optional:
-    Yes
-  Value:
-    A list of user ids to invite.
-  Description:
-    This will tell the server to invite everyone in the list to the newly
-    created room.
+The registration/login process breaks down into the following:
+  1. Determine the requirements for logging in.
+  2. Submit the login stage credentials.
+  3. Get credentials or be told the next stage in the login process and repeat 
+     step 2.
+     
+As each home server may have different ways of logging in, the client needs to
+know how they should login. All distinct login stages MUST have a corresponding
+``type``.  A ``type`` is a namespaced string which details the mechanism for
+logging in.
 
-Example::
+A client may be able to login via multiple valid login flows, and should choose
+a single flow when logging in. A flow is a series of login stages. The home
+server MUST respond with all the valid login flows when requested::
 
+  The client can login via 3 paths: 1a and 1b, 2a and 2b, or 3. The client should
+  select one of these paths.
+  
   {
-    "visibility": "public", 
-    "room_alias_name": "the pub",
-    "name": "The Grand Duke Pub",
-    "topic": "All about happy hour"
+    "flows": [
+      {
+        "type": "<login type1a>",
+        "stages": [ "<login type 1a>", "<login type 1b>" ]
+      },
+      {
+        "type": "<login type2a>",
+        "stages": [ "<login type 2a>", "<login type 2b>" ]
+      },
+      {
+        "type": "<login type3>"
+      }
+    ]
   }
 
-The home server will create a ``m.room.create`` event when the room is created,
-which serves as the root of the PDU graph for this room. This event also has a
-``creator`` key which contains the user ID of the room creator. It will also
-generate several other events in order to manage permissions in this room. This
-includes:
+After the login is completed, the client's fully-qualified user ID and a new
+access token MUST be returned::
 
- - ``m.room.power_levels`` : Sets the power levels of users.
- - ``m.room.join_rules`` : Whether the room is "invite-only" or not.
- - ``m.room.add_state_level``: The power level required in order to add new
-   state to the room (as opposed to updating exisiting state)
- - ``m.room.send_event_level`` : The power level required in order to send a
-   message in this room.
- - ``m.room.ops_level`` : The power level required in order to kick or ban a
-   user from the room.
+  {
+    "user_id": "@user:matrix.org",
+    "access_token": "abcdef0123456789"
+  }
 
-See `Room Events`_ for more information on these events.
+The ``user_id`` key is particularly useful if the home server wishes to support
+localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as
+the client may not be able to determine its ``user_id`` in this case.
 
-Modifying aliases
------------------
-.. NOTE::
-  This section is a work in progress.
+If a login has multiple requests, the home server may wish to create a session.
+If a home server responds with a 'session' key to a request, clients MUST
+submit it in subsequent requests until the login is completed::
 
-.. TODO kegan
-    - path to edit aliases 
-    - PUT /directory/room/<room alias>  { room_id : foo }
-    - GET /directory/room/<room alias> { room_id : foo, servers: [a.com, b.com] }
-    - format when retrieving list of aliases. NOT complete list.
-    - format for adding/removing aliases.
+  {
+    "session": "<session id>"
+  }
 
-Permissions
------------
-.. NOTE::
-  This section is a work in progress.
+This specification defines the following login types:
+ - ``m.login.password``
+ - ``m.login.oauth2``
+ - ``m.login.email.code``
+ - ``m.login.email.url``
+ - ``m.login.email.identity``
 
-.. TODO kegan
-    - TODO: What is a power level? How do they work? Defaults / required levels for X. How do they change
-      as people join and leave rooms? What do you do if you get a clash? Examples.
-    - TODO: List all actions which use power levels (sending msgs, inviting users, banning people, etc...)
-    - TODO: Room config - what is the event and what are the keys/values and explanations for them.
-      Link through to respective sections where necessary. How does this tie in with permissions, e.g.
-      give example of creating a read-only room.
+Password-based
+--------------
+:Type: 
+  ``m.login.password``
+:Description: 
+  Login is supported via a username and password.
 
-Permissions for rooms are done via the concept of power levels - to do any
-action in a room a user must have a suitable power level. 
+To respond to this type, reply with::
 
-Power levels for users are defined in ``m.room.power_levels``, where both a
-default and specific users' power levels can be set. By default all users have
-a power level of 0, other than the room creator whose power level defaults to
-100. Power levels for users are tracked per-room even if the user is not
-present in the room.
+  {
+    "type": "m.login.password",
+    "user": "<user_id or user localpart>",
+    "password": "<password>"
+  }
 
-State events may contain a ``required_power_level`` key, which indicates the
-minimum power a user must have before they can update that state key. The only
-exception to this is when a user leaves a room.
+The home server MUST respond with either new credentials, the next stage of the
+login process, or a standard error response.
 
-To perform certain actions there are additional power level requirements
-defined in the following state events:
+OAuth2-based
+------------
+:Type: 
+  ``m.login.oauth2``
+:Description:
+  Login is supported via OAuth2 URLs. This login consists of multiple requests.
 
-- ``m.room.send_event_level`` defines the minimum level for sending non-state 
-  events. Defaults to 50.
-- ``m.room.add_state_level`` defines the minimum level for adding new state,
-  rather than updating existing state. Defaults to 50.
-- ``m.room.ops_level`` defines the minimum levels to ban and kick other users.
-  This defaults to a kick and ban levels of 50 each.
+To respond to this type, reply with::
 
+  {
+    "type": "m.login.oauth2",
+    "user": "<user_id or user localpart>"
+  }
 
-Joining rooms
--------------
-.. TODO kegan
-  - TODO: What does the home server have to do to join a user to a room?
+The server MUST respond with::
 
-Users need to join a room in order to send and receive events in that room. A
-user can join a room by making a request to |/join/<room_alias_or_id>|_ with::
+  {
+    "uri": <Authorization Request URI OR service selection URI>
+  }
 
-  {}
+The home server acts as a 'confidential' client for the purposes of OAuth2.  If
+the uri is a ``sevice selection URI``, it MUST point to a webpage which prompts
+the user to choose which service to authorize with. On selection of a service,
+this MUST link through to an ``Authorization Request URI``. If there is only 1
+service which the home server accepts when logging in, this indirection can be
+skipped and the "uri" key can be the ``Authorization Request URI``. 
 
-Alternatively, a user can make a request to |/rooms/<room_id>/join|_ with the
-same request content.  This is only provided for symmetry with the other
-membership APIs: ``/rooms/<room id>/invite`` and ``/rooms/<room id>/leave``. If
-a room alias was specified, it will be automatically resolved to a room ID,
-which will then be joined. The room ID that was joined will be returned in
-response::
+The client then visits the ``Authorization Request URI``, which then shows the
+OAuth2 Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with the
+auth code.  Home servers can choose any path for the ``redirect URI``. The
+client should visit the ``redirect URI``, which will then finish the OAuth2
+login process, granting the home server an access token for the chosen service.
+When the home server gets this access token, it verifies that the cilent has
+authorised with the 3rd party, and can now complete the login. The OAuth2
+``redirect URI`` (with auth code) MUST respond with either new credentials, the
+next stage of the login process, or a standard error response.
+    
+For example, if a home server accepts OAuth2 from Google, it would return the 
+Authorization Request URI for Google::
 
   {
-    "room_id": "!roomid:domain"
+    "uri": "https://accounts.google.com/o/oauth2/auth?response_type=code&
+    client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos"
   }
 
-The membership state for the joining user can also be modified directly to be
-``join`` by sending the following request to
-``/rooms/<room id>/state/m.room.member/<url encoded user id>``::
+The client then visits this URI and authorizes the home server. The client then
+visits the REDIRECT_URI with the auth code= query parameter which returns::
 
   {
-    "membership": "join"
+    "user_id": "@user:matrix.org",
+    "access_token": "0123456789abcdef"
   }
 
-See the `Room events`_ section for more information on ``m.room.member``.
-
-After the user has joined a room, they will receive subsequent events in that
-room. This room will now appear as an entry in the |initialSync|_ API.
-
-Some rooms enforce that a user is *invited* to a room before they can join that
-room. Other rooms will allow anyone to join the room even if they have not
-received an invite.
-
-Inviting users
---------------
-.. TODO kegan
-  - Can invite users to a room if the room config key TODO is set to TODO. Must have required power level.
-  - Outline invite join dance. What is it? Why is it required? How does it work?
-  - What does the home server have to do?
-  - TODO: In what circumstances will direct member editing NOT be equivalent to ``/invite``?
+Email-based (code)
+------------------
+:Type: 
+  ``m.login.email.code``
+:Description:
+  Login is supported by typing in a code which is sent in an email. This login 
+  consists of multiple requests.
 
-The purpose of inviting users to a room is to notify them that the room exists
-so they can choose to become a member of that room. Some rooms require that all
-users who join a room are previously invited to it (an "invite-only" room).
-Whether a given room is an "invite-only" room is determined by the room config
-key ``TODO``. It can have one of the following values:
+To respond to this type, reply with::
 
- - TODO Room config invite only value explanation
- - TODO Room config free-to-join value explanation
+  {
+    "type": "m.login.email.code",
+    "user": "<user_id or user localpart>",
+    "email": "<email address>"
+  }
 
-Only users who have a membership state of ``join`` in a room can invite new
-users to said room. The person being invited must not be in the ``join`` state
-in the room. The fully-qualified user ID must be specified when inviting a
-user, as the user may reside on a different home server. To invite a user, send
-the following request to |/rooms/<room_id>/invite|_, which will manage the
-entire invitation process::
+After validating the email address, the home server MUST send an email
+containing an authentication code and return::
 
   {
-    "user_id": "<user id to invite>"
+    "type": "m.login.email.code",
+    "session": "<session id>"
   }
 
-Alternatively, the membership state for this user in this room can be modified 
-directly by sending the following request to 
-``/rooms/<room id>/state/m.room.member/<url encoded user id>``::
+The second request in this login stage involves sending this authentication
+code::
 
   {
-    "membership": "invite"
+    "type": "m.login.email.code",
+    "session": "<session id>",
+    "code": "<code in email sent>"
   }
 
-See the `Room events`_ section for more information on ``m.room.member``.
+The home server MUST respond to this with either new credentials, the next
+stage of the login process, or a standard error response.
 
-Leaving rooms
--------------
-.. TODO kegan
-  - TODO: Grace period before deletion?
-  - TODO: Under what conditions should a room NOT be purged?
+Email-based (url)
+-----------------
+:Type: 
+  ``m.login.email.url``
+:Description:
+  Login is supported by clicking on a URL in an email. This login consists of 
+  multiple requests.
 
+To respond to this type, reply with::
 
-A user can leave a room to stop receiving events for that room. A user must
-have joined the room before they are eligible to leave the room. If the room is
-an "invite-only" room, they will need to be re-invited before they can re-join
-the room.  To leave a room, a request should be made to
-|/rooms/<room_id>/leave|_ with::
+  {
+    "type": "m.login.email.url",
+    "user": "<user_id or user localpart>",
+    "email": "<email address>"
+  }
 
-  {}
+After validating the email address, the home server MUST send an email
+containing an authentication URL and return::
 
-Alternatively, the membership state for this user in this room can be modified 
-directly by sending the following request to 
-``/rooms/<room id>/state/m.room.member/<url encoded user id>``::
+  {
+    "type": "m.login.email.url",
+    "session": "<session id>"
+  }
+
+The email contains a URL which must be clicked. After it has been clicked, the
+client should perform another request::
 
   {
-    "membership": "leave"
+    "type": "m.login.email.url",
+    "session": "<session id>"
   }
 
-See the `Room events`_ section for more information on ``m.room.member``.
+The home server MUST respond to this with either new credentials, the next
+stage of the login process, or a standard error response. 
 
-Once a user has left a room, that room will no longer appear on the
-|initialSync|_ API. Be aware that leaving a room is not equivalent to have
-never been in that room. A user who has previously left a room still maintains
-some residual state in that room. Their membership state will be marked as
-``leave``. This contrasts with a user who has *never been invited or joined to
-that room* who will not have any membership state for that room. 
+A common client implementation will be to periodically poll until the link is
+clicked.  If the link has not been visited yet, a standard error response with
+an errcode of ``M_LOGIN_EMAIL_URL_NOT_YET`` should be returned.
 
-If all members in a room leave, that room becomes eligible for deletion. 
 
-Banning users in a room
------------------------
-A user may decide to ban another user in a room. 'Banning' forces the target
-user to leave the room and prevents them from re-joining the room. A banned
-user will not be treated as a joined user, and so will not be able to send or
-receive events in the room. In order to ban someone, the user performing the
-ban MUST have the required power level. To ban a user, a request should be made
-to |/rooms/<room_id>/ban|_ with::
+Email-based (identity server)
+-----------------------------
+:Type:
+  ``m.login.email.identity``
+:Description:
+  Login is supported by authorising an email address with an identity server.
 
-  {
-    "user_id": "<user id to ban"
-    "reason": "string: <reason for the ban>"
-  }
-  
-Banning a user adjusts the banned member's membership state to ``ban`` and
-adjusts the power level of this event to a level higher than the banned person.
-Like with other membership changes, a user can directly adjust the target
-member's state, by making a request to
-``/rooms/<room id>/state/m.room.member/<user id>``::
+Prior to submitting this, the client should authenticate with an identity
+server.  After authenticating, the session information should be submitted to
+the home server.
+
+To respond to this type, reply with::
 
   {
-    "membership": "ban"
+    "type": "m.login.email.identity",
+    "threepidCreds": [
+      {
+        "sid": "<identity server session id>",
+        "clientSecret": "<identity server client secret>",
+        "idServer": "<url of identity server authed with, e.g. 'matrix.org:8090'>"
+      }
+    ]
   }
 
-Events in a room
-----------------
-Room events can be split into two categories:
-
-:State Events:
-  These are events which replace events that came before it, depending on a set
-  of unique keys.  These keys are the event ``type`` and a ``state_key``.
-  Events with the same set of keys will be overwritten. Typically, state events
-  are used to store state, hence their name.
-
-:Non-state events:
-  These are events which cannot be overwritten after sending. The list of
-  events continues to grow as more events are sent. As this list grows, it
-  becomes necessary to provide a mechanism for navigating this list. Pagination
-  APIs are used to view the list of historical non-state events. Typically,
-  non-state events are used to send messages.
 
-This specification outlines several events, all with the event type prefix
-``m.``. However, applications may wish to add their own type of event, and this
-can be achieved using the REST API detailed in the following sections. If new
-events are added, the event ``type`` key SHOULD follow the Java package naming
-convention, e.g. ``com.example.myapp.event``.  This ensures event types are
-suitably namespaced for each application and reduces the risk of clashes.
 
-State events
-------------
-State events can be sent by ``PUT`` ing to
-|/rooms/<room_id>/state/<event_type>/<state_key>|_.  These events will be
-overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all match.
-If the state event has no ``state_key``, it can be omitted from the path. These
-requests **cannot use transaction IDs** like other ``PUT`` paths because they
-cannot be differentiated from the ``state_key``. Furthermore, ``POST`` is
-unsupported on state paths. Valid requests look like::
+N-Factor Authentication
+-----------------------
+Multiple login stages can be combined to create N-factor authentication during
+login.
 
-  PUT /rooms/!roomid:domain/state/m.example.event
-  { "key" : "without a state key" }
+This can be achieved by responding with the ``next`` login type on completion
+of a previous login stage::
 
-  PUT /rooms/!roomid:domain/state/m.another.example.event/foo
-  { "key" : "with 'foo' as the state key" }
+  {
+    "next": "<next login type>"
+  }
 
-In contrast, these requests are invalid::
+If a home server implements N-factor authentication, it MUST respond with all 
+``stages`` when initially queried for their login requirements::
 
-  POST /rooms/!roomid:domain/state/m.example.event/
-  { "key" : "cannot use POST here" }
+  {
+    "type": "<1st login type>",
+    "stages": [ <1st login type>, <2nd login type>, ... , <Nth login type> ]
+  }
 
-  PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
-  { "key" : "txnIds are not supported" }
+This can be represented conceptually as::
 
-Care should be taken to avoid setting the wrong ``state key``::
+   _______________________
+  |    Login Stage 1      |
+  | type: "<login type1>" |
+  |  ___________________  |
+  | |_Request_1_________| | <-- Returns "session" key which is used throughout.
+  |  ___________________  |     
+  | |_Request_2_________| | <-- Returns a "next" value of "login type2"
+  |_______________________|
+            |
+            |
+   _________V_____________
+  |    Login Stage 2      |
+  | type: "<login type2>" |
+  |  ___________________  |
+  | |_Request_1_________| |
+  |  ___________________  |
+  | |_Request_2_________| |
+  |  ___________________  |
+  | |_Request_3_________| | <-- Returns a "next" value of "login type3"
+  |_______________________|
+            |
+            |
+   _________V_____________
+  |    Login Stage 3      |
+  | type: "<login type3>" |
+  |  ___________________  |
+  | |_Request_1_________| | <-- Returns user credentials
+  |_______________________|
 
-  PUT /rooms/!roomid:domain/state/m.another.example.event/11
-  { "key" : "with '11' as the state key, but was probably intended to be a txnId" }
+Fallback
+--------
+Clients cannot be expected to be able to know how to process every single login
+type. If a client determines it does not know how to handle a given login type,
+it should request a login fallback page::
 
-The ``state_key`` is often used to store state about individual users, by using
-the user ID as the ``state_key`` value. For example::
+  GET matrix/client/api/v1/login/fallback
 
-  PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Adomain.com
-  { "animal" : "cat", "reason": "fluffy" }
+This MUST return an HTML page which can perform the entire login process.
 
-In some cases, there may be no need for a ``state_key``, so it can be omitted::
 
-  PUT /rooms/!roomid:domain/state/m.room.bgd.color
-  { "color": "red", "hex": "#ff0000" }
+Rooms
+=====
 
-See `Room Events`_ for the ``m.`` event specification.
+Creation
+--------
+.. TODO kegan
+  - TODO: Key for invite these users?
+  
+To create a room, a client has to use the |createRoom|_ API. There are various
+options which can be set when creating a room:
 
-Non-state events
-----------------
-Non-state events can be sent by sending a request to
-|/rooms/<room_id>/send/<event_type>|_.  These requests *can* use transaction
-IDs and ``PUT``/``POST`` methods. Non-state events allow access to historical
-events and pagination, making it best suited for sending messages.  For
-example::
+``visibility``
+  Type: 
+    String
+  Optional: 
+    Yes
+  Value:
+    Either ``public`` or ``private``.
+  Description:
+    A ``public`` visibility indicates that the room will be shown in the public
+    room list. A ``private`` visibility will hide the room from the public room
+    list. Rooms default to ``public`` visibility if this key is not included.
 
-  POST /rooms/!roomid:domain/send/m.custom.example.message
-  { "text": "Hello world!" }
+``room_alias_name``
+  Type: 
+    String
+  Optional: 
+    Yes
+  Value:
+    The room alias localpart.
+  Description:
+    If this is included, a room alias will be created and mapped to the newly
+    created room.  The alias will belong on the same home server which created
+    the room, e.g.  ``!qadnasoi:domain.com >>> #room_alias_name:domain.com``
 
-  PUT /rooms/!roomid:domain/send/m.custom.example.message/11
-  { "text": "Goodbye world!" }
+``name``
+  Type: 
+    String
+  Optional: 
+    Yes
+  Value:
+    The ``name`` value for the ``m.room.name`` state event.
+  Description:
+    If this is included, an ``m.room.name`` event will be sent into the room to
+    indicate the name of the room. See `Room Events`_ for more information on
+    ``m.room.name``.
 
-See `Room Events`_ for the ``m.`` event specification.
+``topic``
+  Type: 
+    String
+  Optional: 
+    Yes
+  Value:
+    The ``topic`` value for the ``m.room.topic`` state event.
+  Description:
+    If this is included, an ``m.room.topic`` event will be sent into the room
+    to indicate the topic for the room. See `Room Events`_ for more information
+    on ``m.room.topic``.
 
-Syncing rooms
--------------
+``invite``
+  Type:
+    List
+  Optional:
+    Yes
+  Value:
+    A list of user ids to invite.
+  Description:
+    This will tell the server to invite everyone in the list to the newly
+    created room.
+
+Example::
+
+  {
+    "visibility": "public", 
+    "room_alias_name": "the pub",
+    "name": "The Grand Duke Pub",
+    "topic": "All about happy hour"
+  }
+
+The home server will create a ``m.room.create`` event when the room is created,
+which serves as the root of the PDU graph for this room. This event also has a
+``creator`` key which contains the user ID of the room creator. It will also
+generate several other events in order to manage permissions in this room. This
+includes:
+
+ - ``m.room.power_levels`` : Sets the power levels of users.
+ - ``m.room.join_rules`` : Whether the room is "invite-only" or not.
+ - ``m.room.add_state_level``: The power level required in order to add new
+   state to the room (as opposed to updating exisiting state)
+ - ``m.room.send_event_level`` : The power level required in order to send a
+   message in this room.
+ - ``m.room.ops_level`` : The power level required in order to kick or ban a
+   user from the room.
+
+See `Room Events`_ for more information on these events.
+
+Modifying aliases
+-----------------
 .. NOTE::
   This section is a work in progress.
 
-When a client logs in, they may have a list of rooms which they have already
-joined. These rooms may also have a list of events associated with them. The
-purpose of 'syncing' is to present the current room and event information in a
-convenient, compact manner. The events returned are not limited to room events;
-presence events will also be returned. There are two APIs provided:
-
- - |initialSync|_ : A global sync which will present room and event information
-   for all rooms the user has joined.
+.. TODO kegan
+    - path to edit aliases 
+    - PUT /directory/room/<room alias>  { room_id : foo }
+    - GET /directory/room/<room alias> { room_id : foo, servers: [a.com, b.com] }
+    - format when retrieving list of aliases. NOT complete list.
+    - format for adding/removing aliases.
 
- - |/rooms/<room_id>/initialSync|_ : A sync scoped to a single room. Presents
-   room and event information for this room only.
+Permissions
+-----------
+.. NOTE::
+  This section is a work in progress.
 
 .. TODO kegan
-  - TODO: JSON response format for both types
-  - TODO: when would you use global? when would you use scoped?
+    - TODO: What is a power level? How do they work? Defaults / required levels for X. How do they change
+      as people join and leave rooms? What do you do if you get a clash? Examples.
+    - TODO: List all actions which use power levels (sending msgs, inviting users, banning people, etc...)
+    - TODO: Room config - what is the event and what are the keys/values and explanations for them.
+      Link through to respective sections where necessary. How does this tie in with permissions, e.g.
+      give example of creating a read-only room.
 
-Getting events for a room
--------------------------
-There are several APIs provided to ``GET`` events for a room:
+Permissions for rooms are done via the concept of power levels - to do any
+action in a room a user must have a suitable power level. 
 
-``/rooms/<room id>/state/<event type>/<state key>``
-  Description:
-    Get the state event identified.
-  Response format:
-    A JSON object representing the state event **content**.
-  Example:
-    ``/rooms/!room:domain.com/state/m.room.name`` returns ``{ "name": "Room name" }``
+Power levels for users are defined in ``m.room.power_levels``, where both a
+default and specific users' power levels can be set. By default all users have
+a power level of 0, other than the room creator whose power level defaults to
+100. Power levels for users are tracked per-room even if the user is not
+present in the room.
 
-|/rooms/<room_id>/state|_
-  Description:
-    Get all state events for a room.
-  Response format:
-    ``[ { state event }, { state event }, ... ]``
-  Example:
-    TODO
+State events may contain a ``required_power_level`` key, which indicates the
+minimum power a user must have before they can update that state key. The only
+exception to this is when a user leaves a room.
 
+To perform certain actions there are additional power level requirements
+defined in the following state events:
 
-|/rooms/<room_id>/members|_
-  Description:
-    Get all ``m.room.member`` state events.
-  Response format:
-    ``{ "start": "<token>", "end": "<token>", "chunk": [ { m.room.member event }, ... ] }``
-  Example:
-    TODO
+- ``m.room.send_event_level`` defines the minimum level for sending non-state 
+  events. Defaults to 50.
+- ``m.room.add_state_level`` defines the minimum level for adding new state,
+  rather than updating existing state. Defaults to 50.
+- ``m.room.ops_level`` defines the minimum levels to ban and kick other users.
+  This defaults to a kick and ban levels of 50 each.
 
-|/rooms/<room_id>/messages|_
-  Description:
-    Get all ``m.room.message`` and ``m.room.member`` events. This API supports
-    pagination using ``from`` and ``to`` query parameters, coupled with the
-    ``start`` and ``end`` tokens from an |initialSync|_ API.
-  Response format:
-    ``{ "start": "<token>", "end": "<token>" }``
-  Example:
-    TODO
-    
-|/rooms/<room_id>/initialSync|_
-  Description:
-    Get all relevant events for a room. This includes state events, paginated non-state
-    events and presence events.
-  Response format:
-    `` { TODO } ``
-  Example:
-    TODO
 
+Joining rooms
+-------------
+.. TODO kegan
+  - TODO: What does the home server have to do to join a user to a room?
 
-Room Events
-===========
-.. NOTE::
-  This section is a work in progress.
+Users need to join a room in order to send and receive events in that room. A
+user can join a room by making a request to |/join/<room_alias_or_id>|_ with::
 
-.. TODO dave?
-  - voip events?
+  {}
 
-This specification outlines several standard event types, all of which are
-prefixed with ``m.``
+Alternatively, a user can make a request to |/rooms/<room_id>/join|_ with the
+same request content.  This is only provided for symmetry with the other
+membership APIs: ``/rooms/<room id>/invite`` and ``/rooms/<room id>/leave``. If
+a room alias was specified, it will be automatically resolved to a room ID,
+which will then be joined. The room ID that was joined will be returned in
+response::
 
-``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.
+  {
+    "room_id": "!roomid:domain"
+  }
 
-``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.
+The membership state for the joining user can also be modified directly to be
+``join`` by sending the following request to
+``/rooms/<room id>/state/m.room.member/<url encoded user id>``::
 
-``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.
+  {
+    "membership": "join"
+  }
 
-``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.
+See the `Room events`_ section for more information on ``m.room.member``.
 
-``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 : 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.
+After the user has joined a room, they will receive subsequent events in that
+room. This room will now appear as an entry in the |initialSync|_ API.
 
-``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.
+Some rooms enforce that a user is *invited* to a room before they can join that
+room. Other rooms will allow anyone to join the room even if they have not
+received an invite.
 
-``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> }``
-  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.
+Inviting users
+--------------
+.. TODO kegan
+  - Can invite users to a room if the room config key TODO is set to TODO. Must have required power level.
+  - Outline invite join dance. What is it? Why is it required? How does it work?
+  - What does the home server have to do?
+  - TODO: In what circumstances will direct member editing NOT be equivalent to ``/invite``?
 
-``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:
-    A server `may` inform the room that it has added or removed an alias for
-    the room. This is purely for informational purposes and may become stale.
-    Clients `should` check that the room alias is still valid before using it.
-    The ``state_key`` of the event is the homeserver which owns the room alias.
+The purpose of inviting users to a room is to notify them that the room exists
+so they can choose to become a member of that room. Some rooms require that all
+users who join a room are previously invited to it (an "invite-only" room).
+Whether a given room is an "invite-only" room is determined by the room config
+key ``TODO``. It can have one of the following values:
 
-``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`_.
+ - TODO Room config invite only value explanation
+ - TODO Room config free-to-join value explanation
 
-``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. 
+Only users who have a membership state of ``join`` in a room can invite new
+users to said room. The person being invited must not be in the ``join`` state
+in the room. The fully-qualified user ID must be specified when inviting a
+user, as the user may reside on a different home server. To invite a user, send
+the following request to |/rooms/<room_id>/invite|_, which will manage the
+entire invitation process::
 
-m.room.message msgtypes
------------------------
-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:
+  {
+    "user_id": "<user id to invite>"
+  }
 
-``m.text``
-  Required keys:
-    - ``body`` : "string" - The body of the message.
-  Optional keys:
-    None.
-  Example:
-    ``{ "msgtype": "m.text", "body": "I am a fish" }``
+Alternatively, the membership state for this user in this room can be modified 
+directly by sending the following request to 
+``/rooms/<room id>/state/m.room.member/<url encoded user id>``::
 
-``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" }``
+  {
+    "membership": "invite"
+  }
 
-``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".
+See the `Room events`_ section for more information on ``m.room.member``.
 
-  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)",
-      }
+Leaving rooms
+-------------
+.. TODO kegan
+  - TODO: Grace period before deletion?
+  - TODO: Under what conditions should a room NOT be purged?
 
-``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),
-      }
+A user can leave a room to stop receiving events for that room. A user must
+have joined the room before they are eligible to leave the room. If the room is
+an "invite-only" room, they will need to be re-invited before they can re-join
+the room.  To leave a room, a request should be made to
+|/rooms/<room_id>/leave|_ with::
 
-``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::
+Alternatively, the membership state for this user in this room can be modified 
+directly by sending the following request to 
+``/rooms/<room id>/state/m.room.member/<url encoded user id>``::
 
-      {
-        "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)
-      }
+  {
+    "membership": "leave"
+  }
 
-``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".
+See the `Room events`_ section for more information on ``m.room.member``.
 
-The following keys can be attached to any ``m.room.message``:
+Once a user has left a room, that room will no longer appear on the
+|initialSync|_ API. Be aware that leaving a room is not equivalent to have
+never been in that room. A user who has previously left a room still maintains
+some residual state in that room. Their membership state will be marked as
+``leave``. This contrasts with a user who has *never been invited or joined to
+that room* who will not have any membership state for that room. 
 
-  Optional keys:
-    - ``sender_ts`` : integer - A timestamp (ms resolution) representing the
-      wall-clock time when the message was sent from the client.
+If all members in a room leave, that room becomes eligible for deletion. 
 
-Presence
-========
-.. NOTE::
-  This section is a work in progress.
+Banning users in a room
+-----------------------
+A user may decide to ban another user in a room. 'Banning' forces the target
+user to leave the room and prevents them from re-joining the room. A banned
+user will not be treated as a joined user, and so will not be able to send or
+receive events in the room. In order to ban someone, the user performing the
+ban MUST have the required power level. To ban a user, a request should be made
+to |/rooms/<room_id>/ban|_ with::
 
-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:
+  {
+    "user_id": "<user id to ban"
+    "reason": "string: <reason for the ban>"
+  }
+  
+Banning a user adjusts the banned member's membership state to ``ban`` and
+adjusts the power level of this event to a level higher than the banned person.
+Like with other membership changes, a user can directly adjust the target
+member's state, by making a request to
+``/rooms/<room id>/state/m.room.member/<user id>``::
 
-  - ``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`` : TODO. Behaves as offline, but allows the user to see the
-    client state anyway and generally interact with client features.
+  {
+    "membership": "ban"
+  }
 
-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.
+Events in a room
+----------------
+Room events can be split into two categories:
 
-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.
+:State Events:
+  These are events which replace events that came before it, depending on a set
+  of unique keys.  These keys are the event ``type`` and a ``state_key``.
+  Events with the same set of keys will be overwritten. Typically, state events
+  are used to store state, hence their name.
 
-Idle Time
----------
-As well as the basic ``presence`` field, the presence information can also show
-a sense of an "idle timer". This should be maintained individually by the
-user's clients, and the home server can take the highest reported time as that
-to report. When a user is offline, the home server can still report when the
-user was last seen online.
+:Non-state events:
+  These are events which cannot be overwritten after sending. The list of
+  events continues to grow as more events are sent. As this list grows, it
+  becomes necessary to provide a mechanism for navigating this list. Pagination
+  APIs are used to view the list of historical non-state events. Typically,
+  non-state events are used to send messages.
 
-Transmission
+This specification outlines several events, all with the event type prefix
+``m.``. However, applications may wish to add their own type of event, and this
+can be achieved using the REST API detailed in the following sections. If new
+events are added, the event ``type`` key SHOULD follow the Java package naming
+convention, e.g. ``com.example.myapp.event``.  This ensures event types are
+suitably namespaced for each application and reduces the risk of clashes.
+
+State events
 ------------
-.. NOTE::
-  This section is a work in progress.
+State events can be sent by ``PUT`` ing to
+|/rooms/<room_id>/state/<event_type>/<state_key>|_.  These events will be
+overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all match.
+If the state event has no ``state_key``, it can be omitted from the path. These
+requests **cannot use transaction IDs** like other ``PUT`` paths because they
+cannot be differentiated from the ``state_key``. Furthermore, ``POST`` is
+unsupported on state paths. Valid requests look like::
 
-.. TODO:
-  - Transmitted as an EDU.
-  - Presence lists determine who to send to.
+  PUT /rooms/!roomid:domain/state/m.example.event
+  { "key" : "without a state key" }
 
-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.
+  PUT /rooms/!roomid:domain/state/m.another.example.event/foo
+  { "key" : "with 'foo' as the state key" }
 
-Presence and Permissions
-------------------------
-For a viewing user to be allowed to see the presence information of a target
-user, either:
+In contrast, these requests are invalid::
 
- - 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
+  POST /rooms/!roomid:domain/state/m.example.event/
+  { "key" : "cannot use POST here" }
 
-In the latter case, this allows for clients to display some minimal sense of
-presence information in a user list for a room.
+  PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
+  { "key" : "txnIds are not supported" }
 
-Typing notifications
-====================
-.. NOTE::
-  This section is a work in progress.
+Care should be taken to avoid setting the wrong ``state key``::
 
-.. TODO Leo
-    - what is the event type. Are they bundled with other event types? If so, which.
-    - what are the valid keys / values. What do they represent. Any gotchas?
-    - Timeouts. How do they work, who sets them and how do they expire. Does one
-      have priority over another? Give examples.
+  PUT /rooms/!roomid:domain/state/m.another.example.event/11
+  { "key" : "with '11' as the state key, but was probably intended to be a txnId" }
 
-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.
+The ``state_key`` is often used to store state about individual users, by using
+the user ID as the ``state_key`` value. For example::
 
-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.
+  PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Adomain.com
+  { "animal" : "cat", "reason": "fluffy" }
 
-Events
-------
-``m.call.invite``
-This event is sent by the caller when they wish to establish a call.
+In some cases, there may be no need for a ``state_key``, so it can be omitted::
 
-  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[...]" } }``
+  PUT /rooms/!roomid:domain/state/m.room.bgd.color
+  { "color": "red", "hex": "#ff0000" }
 
-``Offer Object``
-  Required keys:
-    - ``type`` : "string" - The type of session description, in this case
-      'offer'
-    - ``sdp`` : "string" - The SDP text of the session description
+See `Room Events`_ for the ``m.`` event specification.
 
-``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.
+Non-state events
+----------------
+Non-state events can be sent by sending a request to
+|/rooms/<room_id>/send/<event_type>|_.  These requests *can* use transaction
+IDs and ``PUT``/``POST`` methods. Non-state events allow access to historical
+events and pagination, making it best suited for sending messages.  For
+example::
 
-  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.
+  POST /rooms/!roomid:domain/send/m.custom.example.message
+  { "text": "Hello world!" }
 
-``Candidate Object``
+  PUT /rooms/!roomid:domain/send/m.custom.example.message/11
+  { "text": "Goodbye world!" }
 
-  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
+See `Room Events`_ for the ``m.`` event specification.
 
-``m.call.answer``
+Syncing rooms
+-------------
+.. NOTE::
+  This section is a work in progress.
 
-  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
+When a client logs in, they may have a list of rooms which they have already
+joined. These rooms may also have a list of events associated with them. The
+purpose of 'syncing' is to present the current room and event information in a
+convenient, compact manner. The events returned are not limited to room events;
+presence events will also be returned. There are two APIs provided:
 
-``Answer Object``
+ - |initialSync|_ : A global sync which will present room and event information
+   for all rooms the user has joined.
 
-  Required keys:
-    - ``type`` : "string" - The type of session description. 'answer' in this
-      case.
-    - ``sdp`` : "string" - The SDP text of the session description
+ - |/rooms/<room_id>/initialSync|_ : A sync scoped to a single room. Presents
+   room and event information for this room only.
 
-``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:
+.. TODO kegan
+  - TODO: JSON response format for both types
+  - TODO: when would you use global? when would you use scoped?
 
-::
+Getting events for a room
+-------------------------
+There are several APIs provided to ``GET`` events for a room:
 
-   Caller                   Callee
- m.call.invite ----------->
- m.call.candidate -------->
- [more candidates events]
-                         User answers call
-                  <------ m.call.answer
-               [...]
-                  <------ m.call.hangup
-                  
-Or a rejected call:
+``/rooms/<room id>/state/<event type>/<state key>``
+  Description:
+    Get the state event identified.
+  Response format:
+    A JSON object representing the state event **content**.
+  Example:
+    ``/rooms/!room:domain.com/state/m.room.name`` returns ``{ "name": "Room name" }``
 
-::
+|/rooms/<room_id>/state|_
+  Description:
+    Get all state events for a room.
+  Response format:
+    ``[ { state event }, { state event }, ... ]``
+  Example:
+    TODO
 
-   Caller                   Callee
- m.call.invite ----------->
- m.call.candidate -------->
- [more candidates events]
-                        User rejects call
-                 <------- m.call.hangup
 
-Calls are negotiated according to the WebRTC specification.
+|/rooms/<room_id>/members|_
+  Description:
+    Get all ``m.room.member`` state events.
+  Response format:
+    ``{ "start": "<token>", "end": "<token>", "chunk": [ { m.room.member event }, ... ] }``
+  Example:
+    TODO
 
+|/rooms/<room_id>/messages|_
+  Description:
+    Get all ``m.room.message`` and ``m.room.member`` events. This API supports
+    pagination using ``from`` and ``to`` query parameters, coupled with the
+    ``start`` and ``end`` tokens from an |initialSync|_ API.
+  Response format:
+    ``{ "start": "<token>", "end": "<token>" }``
+  Example:
+    TODO
+    
+|/rooms/<room_id>/initialSync|_
+  Description:
+    Get all relevant events for a room. This includes state events, paginated non-state
+    events and presence events.
+  Response format:
+    `` { TODO } ``
+  Example:
+    TODO
 
-Glare
------
-This specification aims to address the problem of two users calling each other
-at roughly the same time and their invites crossing on the wire. It is a far
-better experience for the users if their calls are connected if it is clear
-that their intention is to set up a call with one another.
 
-In Matrix, calls are to rooms rather than users (even if those rooms may only
-contain one other user) so we consider calls which are to the same room.
+Room Events
+===========
+.. NOTE::
+  This section is a work in progress.
 
-The rules for dealing with such a situation are as follows:
+.. TODO dave?
+  - voip events?
 
- - If an invite to a room is received whilst the client is preparing to send an
-   invite to the same room, the client should cancel its outgoing call and
-   instead automatically accept the incoming call on behalf of the user.
- - If an invite to a room is received after the client has sent an invite to
-   the same room and is waiting for a response, the client should perform a
-   lexicographical comparison of the call IDs of the two calls and use the
-   lesser of the two calls, aborting the greater. If the incoming call is the
-   lesser, the client should accept this call on behalf of the user.
+This specification outlines several standard event types, all of which are
+prefixed with ``m.``
 
-The call setup should appear seamless to the user as if they had simply placed
-a call and the other party had accepted. Thusly, any media stream that had been
-setup for use on a call should be transferred and used for the call that
-replaces it.
- 
-Profiles
-========
-.. NOTE::
-  This section is a work in progress.
+``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.
 
-.. TODO
-  - Metadata extensibility
-  - Changing profile info generates m.presence events ("presencelike")
-  - keys on m.presence are optional, except presence which is required
-  - m.room.member is populated with the current displayname at that point in time.
-  - That is added by the HS, not you.
-  - Display name changes also generates m.room.member with displayname key f.e. room
-    the user is in.
+``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.
 
-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.
+``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.
 
-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.
+``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 : 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.
 
-Registration and login
-======================
+``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> }``
+  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.
 
-Clients must register with a home server in order to use Matrix. After
-registering, the client will be given an access token which must be used in ALL
-requests to that home server as a query parameter 'access_token'.
+``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:
+    A server `may` inform the room that it has added or removed an alias for
+    the room. This is purely for informational purposes and may become stale.
+    Clients `should` check that the room alias is still valid before using it.
+    The ``state_key`` of the event is the homeserver which owns the room alias.
 
-If the client has already registered, they need to be able to login to their
-account. The home server may provide many different ways of logging in, such as
-user/password auth, login via a social network (OAuth2), login by confirming a
-token sent to their email address, etc. This specification does not define how
-home servers should authorise their users who want to login to their existing
-accounts, but instead defines the standard interface which implementations
-should follow so that ANY client can login to ANY home server. Clients login
-using the |login|_ API. Clients register using the |register|_ API.
-Registration follows the same procedure as login, but the path requests are
-sent to are different.
+``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`_.
 
-The registration/login process breaks down into the following:
-  1. Determine the requirements for logging in.
-  2. Submit the login stage credentials.
-  3. Get credentials or be told the next stage in the login process and repeat 
-     step 2.
-     
-As each home server may have different ways of logging in, the client needs to
-know how they should login. All distinct login stages MUST have a corresponding
-``type``.  A ``type`` is a namespaced string which details the mechanism for
-logging in.
+``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. 
 
-A client may be able to login via multiple valid login flows, and should choose
-a single flow when logging in. A flow is a series of login stages. The home
-server MUST respond with all the valid login flows when requested::
+m.room.message msgtypes
+-----------------------
+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:
 
-  The client can login via 3 paths: 1a and 1b, 2a and 2b, or 3. The client should
-  select one of these paths.
-  
-  {
-    "flows": [
-      {
-        "type": "<login type1a>",
-        "stages": [ "<login type 1a>", "<login type 1b>" ]
-      },
-      {
-        "type": "<login type2a>",
-        "stages": [ "<login type 2a>", "<login type 2b>" ]
-      },
-      {
-        "type": "<login type3>"
-      }
-    ]
-  }
+``m.text``
+  Required keys:
+    - ``body`` : "string" - The body of the message.
+  Optional keys:
+    None.
+  Example:
+    ``{ "msgtype": "m.text", "body": "I am a fish" }``
 
-After the login is completed, the client's fully-qualified user ID and a new
-access token MUST be returned::
+``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" }``
 
-  {
-    "user_id": "@user:matrix.org",
-    "access_token": "abcdef0123456789"
-  }
+``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".
 
-The ``user_id`` key is particularly useful if the home server wishes to support
-localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as
-the client may not be able to determine its ``user_id`` in this case.
+  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)",
+      }
 
-If a login has multiple requests, the home server may wish to create a session.
-If a home server responds with a 'session' key to a request, clients MUST
-submit it in subsequent requests until the login is completed::
+``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::
 
-  {
-    "session": "<session id>"
-  }
+      {
+        "mimetype" : "string (e.g. audio/aac)",
+        "size" : integer (size of audio in bytes),
+        "duration" : integer (duration of audio in milliseconds),
+      }
 
-This specification defines the following login types:
- - ``m.login.password``
- - ``m.login.oauth2``
- - ``m.login.email.code``
- - ``m.login.email.url``
- - ``m.login.email.identity``
+``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".
 
-Password-based
---------------
-:Type: 
-  ``m.login.password``
-:Description: 
-  Login is supported via a username and password.
+  VideoInfo: 
+    Information about a video::
 
-To respond to this type, reply with::
+      {
+        "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)
+      }
 
-  {
-    "type": "m.login.password",
-    "user": "<user_id or user localpart>",
-    "password": "<password>"
-  }
+``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 home server MUST respond with either new credentials, the next stage of the
-login process, or a standard error response.
+The following keys can be attached to any ``m.room.message``:
 
-OAuth2-based
-------------
-:Type: 
-  ``m.login.oauth2``
-:Description:
-  Login is supported via OAuth2 URLs. This login consists of multiple requests.
+  Optional keys:
+    - ``sender_ts`` : integer - A timestamp (ms resolution) representing the
+      wall-clock time when the message was sent from the client.
 
-To respond to this type, reply with::
+Presence
+========
+.. NOTE::
+  This section is a work in progress.
 
-  {
-    "type": "m.login.oauth2",
-    "user": "<user_id or user localpart>"
-  }
+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:
 
-The server MUST respond with::
+  - ``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`` : TODO. Behaves as offline, but allows the user to see the
+    client state anyway and generally interact with client features.
 
-  {
-    "uri": <Authorization Request URI OR service selection URI>
-  }
+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.
 
-The home server acts as a 'confidential' client for the purposes of OAuth2.  If
-the uri is a ``sevice selection URI``, it MUST point to a webpage which prompts
-the user to choose which service to authorize with. On selection of a service,
-this MUST link through to an ``Authorization Request URI``. If there is only 1
-service which the home server accepts when logging in, this indirection can be
-skipped and the "uri" key can be the ``Authorization Request URI``. 
+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.
 
-The client then visits the ``Authorization Request URI``, which then shows the
-OAuth2 Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with the
-auth code.  Home servers can choose any path for the ``redirect URI``. The
-client should visit the ``redirect URI``, which will then finish the OAuth2
-login process, granting the home server an access token for the chosen service.
-When the home server gets this access token, it verifies that the cilent has
-authorised with the 3rd party, and can now complete the login. The OAuth2
-``redirect URI`` (with auth code) MUST respond with either new credentials, the
-next stage of the login process, or a standard error response.
-    
-For example, if a home server accepts OAuth2 from Google, it would return the 
-Authorization Request URI for Google::
+Idle Time
+---------
+As well as the basic ``presence`` field, the presence information can also show
+a sense of an "idle timer". This should be maintained individually by the
+user's clients, and the home server can take the highest reported time as that
+to report. When a user is offline, the home server can still report when the
+user was last seen online.
 
-  {
-    "uri": "https://accounts.google.com/o/oauth2/auth?response_type=code&
-    client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos"
-  }
+Transmission
+------------
+.. NOTE::
+  This section is a work in progress.
 
-The client then visits this URI and authorizes the home server. The client then
-visits the REDIRECT_URI with the auth code= query parameter which returns::
+.. TODO:
+  - Transmitted as an EDU.
+  - Presence lists determine who to send to.
 
-  {
-    "user_id": "@user:matrix.org",
-    "access_token": "0123456789abcdef"
-  }
+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.
 
-Email-based (code)
-------------------
-:Type: 
-  ``m.login.email.code``
-:Description:
-  Login is supported by typing in a code which is sent in an email. This login 
-  consists of multiple requests.
+Presence and Permissions
+------------------------
+For a viewing user to be allowed to see the presence information of a target
+user, either:
 
-To respond to this type, reply with::
+ - 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
 
-  {
-    "type": "m.login.email.code",
-    "user": "<user_id or user localpart>",
-    "email": "<email address>"
-  }
+In the latter case, this allows for clients to display some minimal sense of
+presence information in a user list for a room.
+
+Typing notifications
+====================
+.. NOTE::
+  This section is a work in progress.
 
-After validating the email address, the home server MUST send an email
-containing an authentication code and return::
+.. TODO Leo
+    - what is the event type. Are they bundled with other event types? If so, which.
+    - what are the valid keys / values. What do they represent. Any gotchas?
+    - Timeouts. How do they work, who sets them and how do they expire. Does one
+      have priority over another? Give examples.
 
-  {
-    "type": "m.login.email.code",
-    "session": "<session id>"
-  }
+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.
 
-The second request in this login stage involves sending this authentication
-code::
+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.
 
-  {
-    "type": "m.login.email.code",
-    "session": "<session id>",
-    "code": "<code in email sent>"
-  }
+Events
+------
+``m.call.invite``
+This event is sent by the caller when they wish to establish a call.
 
-The home server MUST respond to this with either new credentials, the next
-stage of the login process, or a standard error response.
+  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[...]" } }``
 
-Email-based (url)
------------------
-:Type: 
-  ``m.login.email.url``
-:Description:
-  Login is supported by clicking on a URL in an email. This login consists of 
-  multiple requests.
+``Offer Object``
+  Required keys:
+    - ``type`` : "string" - The type of session description, in this case
+      'offer'
+    - ``sdp`` : "string" - The SDP text of the session description
 
-To respond to this type, reply with::
+``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.
 
-  {
-    "type": "m.login.email.url",
-    "user": "<user_id or user localpart>",
-    "email": "<email address>"
-  }
+  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.
 
-After validating the email address, the home server MUST send an email
-containing an authentication URL and return::
+``Candidate Object``
 
-  {
-    "type": "m.login.email.url",
-    "session": "<session id>"
-  }
+  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
 
-The email contains a URL which must be clicked. After it has been clicked, the
-client should perform another request::
+``m.call.answer``
 
-  {
-    "type": "m.login.email.url",
-    "session": "<session id>"
-  }
+  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
 
-The home server MUST respond to this with either new credentials, the next
-stage of the login process, or a standard error response. 
+``Answer Object``
 
-A common client implementation will be to periodically poll until the link is
-clicked.  If the link has not been visited yet, a standard error response with
-an errcode of ``M_LOGIN_EMAIL_URL_NOT_YET`` should be returned.
+  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.
 
-Email-based (identity server)
------------------------------
-:Type:
-  ``m.login.email.identity``
-:Description:
-  Login is supported by authorising an email address with an identity server.
+  Required keys:
+    - ``call_id`` : "string" - The ID of the call this event relates to
+    - ``version`` : "integer" - The version of the VoIP specification this
+      messages
 
-Prior to submitting this, the client should authenticate with an identity
-server.  After authenticating, the session information should be submitted to
-the home server.
+Message Exchange
+----------------
+A call is set up with messages exchanged as follows:
 
-To respond to this type, reply with::
+::
 
-  {
-    "type": "m.login.email.identity",
-    "threepidCreds": [
-      {
-        "sid": "<identity server session id>",
-        "clientSecret": "<identity server client secret>",
-        "idServer": "<url of identity server authed with, e.g. 'matrix.org:8090'>"
-      }
-    ]
-  }
+   Caller                   Callee
+ m.call.invite ----------->
+ m.call.candidate -------->
+ [more candidates events]
+                         User answers call
+                  <------ m.call.answer
+               [...]
+                  <------ m.call.hangup
+                  
+Or a rejected call:
 
+::
 
+   Caller                   Callee
+ m.call.invite ----------->
+ m.call.candidate -------->
+ [more candidates events]
+                        User rejects call
+                 <------- m.call.hangup
 
-N-Factor Authentication
------------------------
-Multiple login stages can be combined to create N-factor authentication during
-login.
+Calls are negotiated according to the WebRTC specification.
 
-This can be achieved by responding with the ``next`` login type on completion
-of a previous login stage::
 
-  {
-    "next": "<next login type>"
-  }
+Glare
+-----
+This specification aims to address the problem of two users calling each other
+at roughly the same time and their invites crossing on the wire. It is a far
+better experience for the users if their calls are connected if it is clear
+that their intention is to set up a call with one another.
 
-If a home server implements N-factor authentication, it MUST respond with all 
-``stages`` when initially queried for their login requirements::
+In Matrix, calls are to rooms rather than users (even if those rooms may only
+contain one other user) so we consider calls which are to the same room.
 
-  {
-    "type": "<1st login type>",
-    "stages": [ <1st login type>, <2nd login type>, ... , <Nth login type> ]
-  }
+The rules for dealing with such a situation are as follows:
 
-This can be represented conceptually as::
+ - If an invite to a room is received whilst the client is preparing to send an
+   invite to the same room, the client should cancel its outgoing call and
+   instead automatically accept the incoming call on behalf of the user.
+ - If an invite to a room is received after the client has sent an invite to
+   the same room and is waiting for a response, the client should perform a
+   lexicographical comparison of the call IDs of the two calls and use the
+   lesser of the two calls, aborting the greater. If the incoming call is the
+   lesser, the client should accept this call on behalf of the user.
 
-   _______________________
-  |    Login Stage 1      |
-  | type: "<login type1>" |
-  |  ___________________  |
-  | |_Request_1_________| | <-- Returns "session" key which is used throughout.
-  |  ___________________  |     
-  | |_Request_2_________| | <-- Returns a "next" value of "login type2"
-  |_______________________|
-            |
-            |
-   _________V_____________
-  |    Login Stage 2      |
-  | type: "<login type2>" |
-  |  ___________________  |
-  | |_Request_1_________| |
-  |  ___________________  |
-  | |_Request_2_________| |
-  |  ___________________  |
-  | |_Request_3_________| | <-- Returns a "next" value of "login type3"
-  |_______________________|
-            |
-            |
-   _________V_____________
-  |    Login Stage 3      |
-  | type: "<login type3>" |
-  |  ___________________  |
-  | |_Request_1_________| | <-- Returns user credentials
-  |_______________________|
+The call setup should appear seamless to the user as if they had simply placed
+a call and the other party had accepted. Thusly, any media stream that had been
+setup for use on a call should be transferred and used for the call that
+replaces it.
+ 
+Profiles
+========
+.. NOTE::
+  This section is a work in progress.
 
-Fallback
---------
-Clients cannot be expected to be able to know how to process every single login
-type. If a client determines it does not know how to handle a given login type,
-it should request a login fallback page::
+.. TODO
+  - Metadata extensibility
+  - Changing profile info generates m.presence events ("presencelike")
+  - keys on m.presence are optional, except presence which is required
+  - m.room.member is populated with the current displayname at that point in time.
+  - That is added by the HS, not you.
+  - Display name changes also generates m.room.member with displayname key f.e. room
+    the user is in.
 
-  GET matrix/client/api/v1/login/fallback
+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.
 
-This MUST return an HTML page which can perform the entire login process.
 
 Identity
 ========