Merge branch 'master' into paul/federation-room-join

pull/977/head
Paul "LeoNerd" Evans 9 years ago
commit 2410e8b15a

@ -1,41 +0,0 @@
.. This file is automatically processed by the templating system. To make it
.. happy, you MUST use '=' as the title underline and you MUST stick the version
.. in the title. The version MUST follow the numbering format
.. "v<num>.<num>.<num>" - You cannot use a-z. If the templating system fails to
.. find the right info, it will be treated as a test failure and so will show up
.. in Jenkins. Comments like this are ignored by both RST and the templating
.. system. Add the newest release notes beneath this comment.
Specification changes in v0.2.0 (2015-10-02)
============================================
This update fundamentally restructures the specification. The specification has
been split into more digestible "modules" which each describe a particular
function (e.g. typing). This was done in order make the specification easier to
maintain and help define which modules are mandatory for certain types
of clients. Types of clients along with the mandatory modules can be found in a
new "Feature Profiles" section. This update also begins to aggressively
standardise on using Swagger and JSON Schema to document HTTP endpoints and
Events respectively. It also introduces a number of new concepts to Matrix.
Additions:
- New section: Feature Profiles.
- New section: Receipts.
- New section: Room history visibility.
- New event: ``m.receipt``.
- New event: ``m.room.canonical_alias``
- New event: ``m.room.history_visibility``
- New keys: ``/createRoom`` - allows room "presets" using ``preset`` and
``initial_state`` keys.
- New endpoint: ``/tokenrefresh`` - Related to refreshing access tokens.
Modifications:
- Convert most of the older HTTP APIs to Swagger documentation.
- Convert most of the older event formats to JSON Schema.
- Move selected client-server sections to be "Modules".
Specification changes in v0.1.0 (2015-06-01)
============================================
- First numbered release.
- Restructure the format of Event information. Add more information.
- Restructure the format of the Client-Server HTTP APIs.

@ -49,7 +49,8 @@ def check_parameter(filepath, request, parameter):
# Setting the 'id' tells jsonschema where the file is so that it # Setting the 'id' tells jsonschema where the file is so that it
# can correctly resolve relative $ref references in the schema # can correctly resolve relative $ref references in the schema
schema['id'] = fileurl schema['id'] = fileurl
jsonschema.validate(example, schema) resolver = jsonschema.RefResolver(filepath, schema, handlers={"file": load_yaml})
jsonschema.validate(example, schema, resolver=resolver)
except Exception as e: except Exception as e:
raise ValueError("Error validating JSON schema for %r" % ( raise ValueError("Error validating JSON schema for %r" % (
request request
@ -76,7 +77,8 @@ def check_response(filepath, request, code, response):
# Setting the 'id' tells jsonschema where the file is so that it # Setting the 'id' tells jsonschema where the file is so that it
# can correctly resolve relative $ref references in the schema # can correctly resolve relative $ref references in the schema
schema['id'] = fileurl schema['id'] = fileurl
jsonschema.validate(example, schema) resolver = jsonschema.RefResolver(filepath, schema, handlers={"file": load_yaml})
jsonschema.validate(example, schema, resolver=resolver)
except Exception as e: except Exception as e:
raise ValueError("Error validating JSON schema for %r %r" % ( raise ValueError("Error validating JSON schema for %r %r" % (
request, code request, code
@ -103,6 +105,14 @@ def check_swagger_file(filepath):
check_response(filepath, request, code, response) check_response(filepath, request, code, response)
def load_yaml(path):
if not path.startswith("file:///"):
raise Exception("Bad ref: %s" % (path,))
path = path[len("file://"):]
with open(path, "r") as f:
return yaml.load(f)
if __name__ == '__main__': if __name__ == '__main__':
paths = sys.argv[1:] paths = sys.argv[1:]
if not paths: if not paths:

@ -0,0 +1,109 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Client Config API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/user/{userId}/account_data/{type}":
put:
summary: Set some account_data for the user.
description: |-
Set some account_data for the client. This config is only visible to the user
that set the account_data. The config will be synced to clients in the
top-level ``account_data``.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
required: true
description: |-
The id of the user to set account_data for. The access token must be
authorized to make requests for this user id.
x-example: "@alice:example.com"
- in: path
type: string
name: type
required: true
description: |-
The event type of the account_data to set. Custom types should be
namespaced to avoid clashes.
x-example: "org.example.custom.config"
- in: body
name: content
required: true
description: |-
The content of the account_data
schema:
type: object
example: |-
{"custom_account_data_key": "custom_config_value"}
responses:
200:
description:
The account_data was successfully added.
tags:
- User data
"/user/{userId}/rooms/{roomId}/account_data/{type}":
put:
summary: Set some account_data for the user.
description: |-
Set some account_data for the client on a given room. This config is only
visible to the user that set the account_data. The config will be synced to
clients in the per-room ``account_data``.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
required: true
description: |-
The id of the user to set account_data for. The access token must be
authorized to make requests for this user id.
x-example: "@alice:example.com"
- in: path
type: string
name: roomId
required: true
description: |-
The id of the room to set account_data on.
x-example: "!726s6s6q:example.com"
- in: path
type: string
name: type
required: true
description: |-
The event type of the account_data to set. Custom types should be
namespaced to avoid clashes.
x-example: "org.example.custom.room.config"
- in: body
name: content
required: true
description: |-
The content of the account_data
schema:
type: object
example: |-
{"custom_account_data_key": "custom_account_data_value"}
responses:
200:
description:
The account_data was successfully added.
tags:
- User data

@ -0,0 +1,105 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Administration API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/admin/whois/{userId}":
get:
summary: Gets information about a particular user.
description: |-
Gets information about a particular user.
This API may be restricted to only be called by the user being looked
up, or by a server admin. Server-local administrator privileges are not
specified in this document.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
description: The user to look up.
required: true
x-example: "@peter:rabbit.rocks"
responses:
200:
description: The lookup was successful.
examples:
application/json: |-
{
"user_id": "@peter:rabbit.rocks",
"devices": {
"teapot": {
"sessions": [
{
"connections": [
{
"ip": "127.0.0.1",
"last_seen": 1411996332123,
"user_agent": "curl/7.31.0-DEV"
},
{
"ip": "10.0.0.2",
"last_seen": 1411996332123,
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36"
}
]
}
]
}
}
}
schema:
type: object
properties:
user_id:
type: string
description: The Matrix user ID of the user.
devices:
type: object
description: |-
Each key is an identitfier for one of the user's devices.
additionalProperties:
type: object
title: DeviceInfo
properties:
sessions:
type: array
description: A user's sessions (i.e. what they did with an access token from one login).
items:
type: object
title: SessionInfo
properties:
connections:
type: array
description: Information particular connections in the session.
items:
type: object
title: ConnectionInfo
properties:
ip:
type: string
description: Most recently seen IP address of the session.
last_seen:
type: number
description: Unix timestamp that the session was last active.
user_agent:
type: string
description: User agent string last seen in the session.
tags:
- Server administration

@ -0,0 +1,163 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Account Administrative Contact API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/account/password":
post:
summary: Changes a user's password.
description: |-
This API endpoint uses the User-Interactive Authentication API.
An access token should be submitted to this endpoint if the client has
an active session.
The homeserver may change the flows available depending on whether a
valid access token is provided.
security:
- accessToken: []
parameters:
- in: body
name: body
schema:
type: object
example: |-
{
"new_password": "ihatebananas"
}
properties:
new_password:
type: string
description: The new password for the account.
required: ["new_password"]
responses:
200:
description: The password has been changed.
examples:
application/json: "{}"
schema:
type: object
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
tags:
- User data
"/account/3pid":
get:
summary: Gets a list of a user's third party identifiers.
description: |-
Gets a list of the third party identifiers that the homeserver has
associated with the user's account.
This is *not* the same as the list of third party identifiers bound to
the user's Matrix ID in Identity Servers.
Identifiers in this list may be used by the homeserver as, for example,
identifiers that it will accept to reset the user's account password.
security:
- accessToken: []
responses:
200:
description: The lookup was successful.
examples:
application/json: |-
{
"threepids": [
{
"medium": "email",
"address": "monkey@banana.island"
}
]
}
schema:
type: object
properties:
threepids:
type: array
items:
type: object
title: Third party identifier
properties:
medium:
type: string
description: The medium of the third party identifier.
enum: ["email"]
address:
type: string
description: The third party identifier address.
tags:
- User data
post:
summary: Adds contact information to the user's account.
description: Adds contact information to the user's account.
security:
- accessToken: []
parameters:
- in: body
name: body
schema:
type: object
properties:
threePidCreds:
title: "ThreePidCredentials"
type: object
description: The third party credentials to associate with the account.
properties:
client_secret:
type: string
description: The client secret used in the session with the Identity Server.
id_server:
type: string
description: The Identity Server to use.
sid:
type: string
description: The session identifier given by the Identity Server.
required: ["client_secret", "id_server", "sid"]
bind:
type: boolean
description: |-
Whether the homeserver should also bind this third party
identifier to the account's Matrix ID with the passed identity
server. Default: ``false``.
x-example: true
required: ["threePidCreds"]
example: |-
{
"threePidCreds": {
"id_server": "matrix.org",
"sid": "abc123987",
"client_secret": "d0n'tT3ll"
},
"bind": false
}
responses:
200:
description: The addition was successful.
examples:
application/json: "{}"
schema:
type: object
403:
description: The credentials could not be verified with the identity server.
examples:
application/json: |-
{
"errcode": "M_THREEPID_AUTH_FAILED",
"error": "The third party credentials could not be verified by the identity server."
}
tags:
- User data

@ -1,50 +0,0 @@
{
"apiVersion": "1.0.0",
"swaggerVersion": "1.2",
"apis": [
{
"path": "-login",
"description": "Login operations"
},
{
"path": "-registration",
"description": "Registration operations"
},
{
"path": "-rooms",
"description": "Room operations"
},
{
"path": "-profile",
"description": "Profile operations"
},
{
"path": "-presence",
"description": "Presence operations"
},
{
"path": "-events",
"description": "Event operations"
},
{
"path": "-directory",
"description": "Directory operations"
},
{
"path": "-content",
"description": "Content repository operations"
}
],
"authorizations": {
"token": {
"scopes": []
}
},
"info": {
"title": "Matrix Client-Server API Reference",
"description": "This contains the client-server API for the reference implementation of the home server",
"termsOfServiceUrl": "http://matrix.org",
"license": "Apache 2.0",
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}

@ -1,119 +0,0 @@
{
"apiVersion": "1.0.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:8008/_matrix",
"resourcePath": "/media/v1/",
"apis": [
{
"path": "/media/v1/upload",
"operations": [
{
"method": "POST",
"summary": "Upload some content to the content repository.",
"type": "ContentUploadResponse",
"nickname": "upload_content",
"parameters": [
{
"name": "body",
"description": "The file to upload.",
"required": true,
"type": "file",
"paramType": "body"
}
]
}
]
},
{
"path": "/media/v1/download/{serverName}/{mediaId}",
"operations": [
{
"method": "GET",
"summary": "Get the content stored at this address.",
"type": "file",
"nickname": "download_content",
"parameters": [
{
"name": "serverName",
"description": "The serverName from the mxc://<serverName>/<mediaId> URI (the authority component).",
"required": true,
"type": "string",
"paramType": "path"
},
{
"name": "mediaId",
"description": "The mediaId from the mxc://<serverName>/<mediaId> URI (the path component).",
"required": true,
"type": "string",
"paramType": "path"
}
]
}
]
},
{
"path": "/media/v1/thumbnail/{serverName}/{mediaId}",
"operations": [
{
"method": "GET",
"summary": "Get a thumbnail of the content stored at this address.",
"type": "file",
"nickname": "thumbnail_content",
"parameters": [
{
"name": "serverName",
"description": "The serverName from the mxc://<serverName>/<mediaId> URI (the authority component).",
"required": true,
"type": "string",
"paramType": "path"
},
{
"name": "mediaId",
"description": "The mediaId from the mxc://<serverName>/<mediaId> URI (the path component).",
"required": true,
"type": "string",
"paramType": "path"
},
{
"name": "width",
"description": "The desired width of the thumbnail.",
"required": false,
"type": "integer",
"paramType": "query"
},
{
"name": "height",
"description": "The desired height of the thumbnail.",
"required": false,
"type": "integer",
"paramType": "query"
},
{
"name": "method",
"description": "The desired resizing method.",
"enum": [
"crop",
"scale"
],
"required": false,
"type": "string",
"paramType": "query"
}
]
}
]
}
],
"models": {
"ContentUploadResponse": {
"id": "ContentUploadResponse",
"properties": {
"content_uri": {
"type": "string",
"description": "The mxc:// URI where this content is stored. This is of the form 'mxc://{serverName}/{mediaId}'",
"required": true
}
}
}
}
}

@ -1,101 +0,0 @@
{
"apiVersion": "1.0.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:8008/_matrix/client/api/v1",
"resourcePath": "/directory",
"produces": [
"application/json"
],
"apis": [
{
"path": "/directory/room/{roomAlias}",
"operations": [
{
"method": "GET",
"summary": "Get the room ID corresponding to this room alias.",
"notes": "Volatile: This API is likely to change.",
"type": "DirectoryResponse",
"nickname": "get_room_id_for_alias",
"parameters": [
{
"name": "roomAlias",
"description": "The room alias.",
"required": true,
"type": "string",
"paramType": "path"
}
]
},
{
"method": "PUT",
"summary": "Create a new mapping from room alias to room ID.",
"notes": "Volatile: This API is likely to change.",
"type": "void",
"nickname": "add_room_alias",
"parameters": [
{
"name": "roomAlias",
"description": "The room alias to set.",
"required": true,
"type": "string",
"paramType": "path"
},
{
"name": "body",
"description": "The room ID to set.",
"required": true,
"type": "RoomAliasRequest",
"paramType": "body"
}
]
},
{
"method": "DELETE",
"summary": "Removes a mapping of room alias to room ID.",
"notes": "Only privileged users can perform this action.",
"type": "void",
"nickname": "remove_room_alias",
"parameters": [
{
"name": "roomAlias",
"description": "The room alias to remove.",
"required": true,
"type": "string",
"paramType": "path"
}
]
}
]
}
],
"models": {
"DirectoryResponse": {
"id": "DirectoryResponse",
"properties": {
"room_id": {
"type": "string",
"description": "The fully-qualified room ID.",
"required": true
},
"servers": {
"type": "array",
"items": {
"$ref": "string"
},
"description": "A list of servers that know about this room.",
"required": true
}
}
},
"RoomAliasRequest": {
"id": "RoomAliasRequest",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID to map the alias to.",
"required": true
}
}
}
}
}

@ -1,247 +0,0 @@
{
"apiVersion": "1.0.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:8008/_matrix/client/api/v1",
"resourcePath": "/events",
"produces": [
"application/json"
],
"apis": [
{
"path": "/events",
"operations": [
{
"method": "GET",
"summary": "Listen on the event stream",
"notes": "This can only be done by the logged in user. This will block until an event is received, or until the timeout is reached.",
"type": "PaginationChunk",
"nickname": "get_event_stream",
"parameters": [
{
"name": "from",
"description": "The token to stream from.",
"required": false,
"type": "string",
"paramType": "query"
},
{
"name": "timeout",
"description": "The maximum time in milliseconds to wait for an event.",
"required": false,
"type": "integer",
"paramType": "query"
}
]
}
],
"responseMessages": [
{
"code": 400,
"message": "Bad pagination token."
}
]
},
{
"path": "/events/{eventId}",
"operations": [
{
"method": "GET",
"summary": "Get information about a single event.",
"notes": "Get information about a single event.",
"type": "Event",
"nickname": "get_event",
"parameters": [
{
"name": "eventId",
"description": "The event ID to get.",
"required": true,
"type": "string",
"paramType": "path"
}
],
"responseMessages": [
{
"code": 404,
"message": "Event not found."
}
]
}
]
},
{
"path": "/initialSync",
"operations": [
{
"method": "GET",
"summary": "Get this user's current state.",
"notes": "Get this user's current state.",
"type": "InitialSyncResponse",
"nickname": "initial_sync",
"parameters": [
{
"name": "limit",
"description": "The maximum number of messages to return for each room.",
"type": "integer",
"paramType": "query",
"required": false
}
]
}
]
},
{
"path": "/publicRooms",
"operations": [
{
"method": "GET",
"summary": "Get a list of publicly visible rooms.",
"type": "PublicRoomsPaginationChunk",
"nickname": "get_public_room_list"
}
]
}
],
"models": {
"PaginationChunk": {
"id": "PaginationChunk",
"properties": {
"start": {
"type": "string",
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
"required": true
},
"end": {
"type": "string",
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
"required": true
},
"chunk": {
"type": "array",
"description": "An array of events.",
"required": true,
"items": {
"$ref": "Event"
}
}
}
},
"Event": {
"id": "Event",
"properties": {
"event_id": {
"type": "string",
"description": "An ID which uniquely identifies this event.",
"required": true
},
"room_id": {
"type": "string",
"description": "The room in which this event occurred.",
"required": true
}
}
},
"PublicRoomInfo": {
"id": "PublicRoomInfo",
"properties": {
"aliases": {
"type": "array",
"description": "A list of room aliases for this room.",
"items": {
"$ref": "string"
}
},
"name": {
"type": "string",
"description": "The name of the room, as given by the m.room.name state event."
},
"room_id": {
"type": "string",
"description": "The room ID for this public room.",
"required": true
},
"topic": {
"type": "string",
"description": "The topic of this room, as given by the m.room.topic state event."
}
}
},
"PublicRoomsPaginationChunk": {
"id": "PublicRoomsPaginationChunk",
"properties": {
"start": {
"type": "string",
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
"required": true
},
"end": {
"type": "string",
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
"required": true
},
"chunk": {
"type": "array",
"description": "A list of public room data.",
"required": true,
"items": {
"$ref": "PublicRoomInfo"
}
}
}
},
"InitialSyncResponse": {
"id": "InitialSyncResponse",
"properties": {
"end": {
"type": "string",
"description": "A streaming token which can be used with /events to continue from this snapshot of data.",
"required": true
},
"presence": {
"type": "array",
"description": "A list of presence events.",
"items": {
"$ref": "Event"
},
"required": false
},
"rooms": {
"type": "array",
"description": "A list of initial sync room data.",
"required": false,
"items": {
"$ref": "InitialSyncRoomData"
}
}
}
},
"InitialSyncRoomData": {
"id": "InitialSyncRoomData",
"properties": {
"membership": {
"type": "string",
"description": "This user's membership state in this room.",
"required": true
},
"room_id": {
"type": "string",
"description": "The ID of this room.",
"required": true
},
"messages": {
"type": "PaginationChunk",
"description": "The most recent messages for this room, governed by the limit parameter.",
"required": false
},
"state": {
"type": "array",
"description": "A list of state events representing the current state of the room.",
"required": false,
"items": {
"$ref": "Event"
}
}
}
}
}
}

@ -1,120 +0,0 @@
{
"apiVersion": "1.0.0",
"apis": [
{
"operations": [
{
"method": "GET",
"nickname": "get_login_info",
"notes": "All login stages MUST be mentioned if there is >1 login type.",
"summary": "Get the login mechanism to use when logging in.",
"type": "LoginFlows"
},
{
"method": "POST",
"nickname": "submit_login",
"notes": "If this is part of a multi-stage login, there MUST be a 'session' key.",
"parameters": [
{
"description": "A login submission",
"name": "body",
"paramType": "body",
"required": true,
"type": "LoginSubmission"
}
],
"responseMessages": [
{
"code": 400,
"message": "Bad login type"
},
{
"code": 400,
"message": "Missing JSON keys"
}
],
"summary": "Submit a login action.",
"type": "LoginResult"
}
],
"path": "/login"
}
],
"basePath": "http://localhost:8008/_matrix/client/api/v1",
"consumes": [
"application/json"
],
"models": {
"LoginFlows": {
"id": "LoginFlows",
"properties": {
"flows": {
"description": "A list of valid login flows.",
"type": "array",
"items": {
"$ref": "LoginInfo"
}
}
}
},
"LoginInfo": {
"id": "LoginInfo",
"properties": {
"stages": {
"description": "Multi-stage login only: An array of all the login types required to login.",
"items": {
"$ref": "string"
},
"type": "array"
},
"type": {
"description": "The login type that must be used when logging in.",
"type": "string"
}
}
},
"LoginResult": {
"id": "LoginResult",
"properties": {
"access_token": {
"description": "The access token for this user's login if this is the final stage of the login process.",
"type": "string"
},
"user_id": {
"description": "The user's fully-qualified user ID.",
"type": "string"
},
"next": {
"description": "Multi-stage login only: The next login type to submit.",
"type": "string"
},
"session": {
"description": "Multi-stage login only: The session token to send when submitting the next login type.",
"type": "string"
}
}
},
"LoginSubmission": {
"id": "LoginSubmission",
"properties": {
"type": {
"description": "The type of login being submitted.",
"type": "string"
},
"session": {
"description": "Multi-stage login only: The session token from an earlier login stage.",
"type": "string"
},
"_login_type_defined_keys_": {
"description": "Keys as defined by the specified login type, e.g. \"user\", \"password\""
}
}
}
},
"produces": [
"application/json"
],
"resourcePath": "/login",
"swaggerVersion": "1.2"
}

@ -1,164 +0,0 @@
{
"apiVersion": "1.0.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:8008/_matrix/client/api/v1",
"resourcePath": "/presence",
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"apis": [
{
"path": "/presence/{userId}/status",
"operations": [
{
"method": "PUT",
"summary": "Update this user's presence state.",
"notes": "This can only be done by the logged in user.",
"type": "void",
"nickname": "update_presence",
"parameters": [
{
"name": "body",
"description": "The new presence state",
"required": true,
"type": "PresenceUpdate",
"paramType": "body"
},
{
"name": "userId",
"description": "The user whose presence to set.",
"required": true,
"type": "string",
"paramType": "path"
}
]
},
{
"method": "GET",
"summary": "Get this user's presence state.",
"notes": "Get this user's presence state.",
"type": "PresenceUpdate",
"nickname": "get_presence",
"parameters": [
{
"name": "userId",
"description": "The user whose presence to get.",
"required": true,
"type": "string",
"paramType": "path"
}
]
}
]
},
{
"path": "/presence/list/{userId}",
"operations": [
{
"method": "GET",
"summary": "Retrieve a list of presences for all of this user's friends.",
"notes": "",
"type": "array",
"items": {
"$ref": "Presence"
},
"nickname": "get_presence_list",
"parameters": [
{
"name": "userId",
"description": "The user whose presence list to get.",
"required": true,
"type": "string",
"paramType": "path"
}
]
},
{
"method": "POST",
"summary": "Add or remove users from this presence list.",
"notes": "Add or remove users from this presence list.",
"type": "void",
"nickname": "modify_presence_list",
"parameters": [
{
"name": "userId",
"description": "The user whose presence list is being modified.",
"required": true,
"type": "string",
"paramType": "path"
},
{
"name": "body",
"description": "The modifications to make to this presence list.",
"required": true,
"type": "PresenceListModifications",
"paramType": "body"
}
]
}
]
}
],
"models": {
"PresenceUpdate": {
"id": "PresenceUpdate",
"properties": {
"presence": {
"type": "string",
"description": "Enum: The presence state.",
"enum": [
"offline",
"unavailable",
"online",
"free_for_chat"
]
},
"status_msg": {
"type": "string",
"description": "The user-defined message associated with this presence state."
}
},
"subTypes": [
"Presence"
]
},
"Presence": {
"id": "Presence",
"properties": {
"last_active_ago": {
"type": "integer",
"format": "int64",
"description": "The last time this user performed an action on their home server."
},
"user_id": {
"type": "string",
"description": "The fully qualified user ID"
}
}
},
"PresenceListModifications": {
"id": "PresenceListModifications",
"properties": {
"invite": {
"type": "array",
"description": "A list of user IDs to add to the list.",
"items": {
"type": "string",
"description": "A fully qualified user ID."
}
},
"drop": {
"type": "array",
"description": "A list of user IDs to remove from the list.",
"items": {
"type": "string",
"description": "A fully qualified user ID."
}
}
}
}
}
}

@ -1,122 +0,0 @@
{
"apiVersion": "1.0.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:8008/_matrix/client/api/v1",
"resourcePath": "/profile",
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"apis": [
{
"path": "/profile/{userId}/displayname",
"operations": [
{
"method": "PUT",
"summary": "Set a display name.",
"notes": "This can only be done by the logged in user.",
"type": "void",
"nickname": "set_display_name",
"parameters": [
{
"name": "body",
"description": "The new display name for this user.",
"required": true,
"type": "DisplayName",
"paramType": "body"
},
{
"name": "userId",
"description": "The user whose display name to set.",
"required": true,
"type": "string",
"paramType": "path"
}
]
},
{
"method": "GET",
"summary": "Get a display name.",
"notes": "This can be done by anyone.",
"type": "DisplayName",
"nickname": "get_display_name",
"parameters": [
{
"name": "userId",
"description": "The user whose display name to get.",
"required": true,
"type": "string",
"paramType": "path"
}
]
}
]
},
{
"path": "/profile/{userId}/avatar_url",
"operations": [
{
"method": "PUT",
"summary": "Set an avatar URL.",
"notes": "This can only be done by the logged in user.",
"type": "void",
"nickname": "set_avatar_url",
"parameters": [
{
"name": "body",
"description": "The new avatar url for this user.",
"required": true,
"type": "AvatarUrl",
"paramType": "body"
},
{
"name": "userId",
"description": "The user whose avatar url to set.",
"required": true,
"type": "string",
"paramType": "path"
}
]
},
{
"method": "GET",
"summary": "Get an avatar url.",
"notes": "This can be done by anyone.",
"type": "AvatarUrl",
"nickname": "get_avatar_url",
"parameters": [
{
"name": "userId",
"description": "The user whose avatar url to get.",
"required": true,
"type": "string",
"paramType": "path"
}
]
}
]
}
],
"models": {
"DisplayName": {
"id": "DisplayName",
"properties": {
"displayname": {
"type": "string",
"description": "The textual display name"
}
}
},
"AvatarUrl": {
"id": "AvatarUrl",
"properties": {
"avatar_url": {
"type": "string",
"description": "A url to an image representing an avatar."
}
}
}
}
}

@ -1,120 +0,0 @@
{
"apiVersion": "1.0.0",
"apis": [
{
"operations": [
{
"method": "GET",
"nickname": "get_registration_info",
"notes": "All login stages MUST be mentioned if there is >1 login type.",
"summary": "Get the login mechanism to use when registering.",
"type": "RegistrationFlows"
},
{
"method": "POST",
"nickname": "submit_registration",
"notes": "If this is part of a multi-stage registration, there MUST be a 'session' key.",
"parameters": [
{
"description": "A registration submission",
"name": "body",
"paramType": "body",
"required": true,
"type": "RegistrationSubmission"
}
],
"responseMessages": [
{
"code": 400,
"message": "Bad login type"
},
{
"code": 400,
"message": "Missing JSON keys"
}
],
"summary": "Submit a registration action.",
"type": "RegistrationResult"
}
],
"path": "/register"
}
],
"basePath": "http://localhost:8008/_matrix/client/api/v1",
"consumes": [
"application/json"
],
"models": {
"RegistrationFlows": {
"id": "RegistrationFlows",
"properties": {
"flows": {
"description": "A list of valid registration flows.",
"type": "array",
"items": {
"$ref": "RegistrationInfo"
}
}
}
},
"RegistrationInfo": {
"id": "RegistrationInfo",
"properties": {
"stages": {
"description": "Multi-stage registration only: An array of all the login types required to registration.",
"items": {
"$ref": "string"
},
"type": "array"
},
"type": {
"description": "The first login type that must be used when logging in.",
"type": "string"
}
}
},
"RegistrationResult": {
"id": "RegistrationResult",
"properties": {
"access_token": {
"description": "The access token for this user's registration if this is the final stage of the registration process.",
"type": "string"
},
"user_id": {
"description": "The user's fully-qualified user ID.",
"type": "string"
},
"next": {
"description": "Multi-stage registration only: The next registration type to submit.",
"type": "string"
},
"session": {
"description": "Multi-stage registration only: The session token to send when submitting the next registration type.",
"type": "string"
}
}
},
"RegistrationSubmission": {
"id": "RegistrationSubmission",
"properties": {
"type": {
"description": "The type of registration being submitted.",
"type": "string"
},
"session": {
"description": "Multi-stage registration only: The session token from an earlier registration stage.",
"type": "string"
},
"_registration_type_defined_keys_": {
"description": "Keys as defined by the specified registration type, e.g. \"user\", \"password\""
}
}
}
},
"produces": [
"application/json"
],
"resourcePath": "/register",
"swaggerVersion": "1.2"
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,78 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Room Banning API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/ban":
post:
summary: Ban a user in the room.
description: |-
Ban a user in the room. If the user is currently in the room, also kick them.
When a user is banned from a room, they may not join it until they are unbanned.
The caller must have the required power level in order to perform this operation.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier (not alias) from which the user should be banned.
required: true
x-example: "!e42d8c:matrix.org"
- in: body
name: body
required: true
schema:
type: object
example: |-
{
"reason": "Telling unfunny jokes",
"user_id": "@cheeky_monkey:matrix.org"
}
properties:
user_id:
type: string
description: The fully qualified user ID of the user being banned.
reason:
type: string
description: The reason the user has been banned.
required: ["user_id"]
responses:
200:
description: The user has been kicked and banned from the room.
examples:
application/json: |-
{}
schema:
type: object
403:
description: |-
You do not have permission to ban the user from the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
- The banner is not currently in the room.
- The banner's power level is insufficient to ban users from the room.
examples:
application/json: |-
{
"errcode": "M_FORBIDDEN",
"error": "You do not have a high enough power level to ban from this room."
}
tags:
- Room membership

@ -1,11 +1,11 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Content Repository API" title: "Matrix Client-Server Content Repository API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
basePath: /_matrix/media/v1 basePath: /_matrix/media/%CLIENT_MAJOR_VERSION%
produces: produces:
- application/json - application/json
- "*/*" - "*/*"
@ -43,6 +43,8 @@ paths:
{ {
"content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
} }
tags:
- Media
"/download/{serverName}/{mediaId}": "/download/{serverName}/{mediaId}":
get: get:
summary: "Download content from the content repository." summary: "Download content from the content repository."
@ -74,6 +76,8 @@ paths:
type: "string" type: "string"
schema: schema:
type: file type: file
tags:
- Media
"/thumbnail/{serverName}/{mediaId}": "/thumbnail/{serverName}/{mediaId}":
get: get:
summary: "Download a thumbnail of the content from the content repository." summary: "Download a thumbnail of the content from the content repository."
@ -123,5 +127,5 @@ paths:
enum: ["image/jpeg", "image/png"] enum: ["image/jpeg", "image/png"]
schema: schema:
type: file type: file
tags:
- Media

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Room Creation API" title: "Matrix Client-Server Room Creation API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -57,7 +57,7 @@ paths:
description: |- description: |-
The desired room alias **local part**. If this is included, a The desired room alias **local part**. If this is included, a
room alias will be created and mapped to the newly created room alias will be created and mapped to the newly created
room. The alias will belong on the *same* home server which room. The alias will belong on the *same* homeserver which
created the room. For example, if this was set to "foo" and created the room. For example, if this was set to "foo" and
sent to the homeserver "example.com" the complete room alias sent to the homeserver "example.com" the complete room alias
would be ``#foo:example.com``. would be ``#foo:example.com``.
@ -146,3 +146,5 @@ paths:
400: 400:
description: > description: >
The request body is malformed or the room alias specified is already taken. The request body is malformed or the room alias specified is already taken.
tags:
- Room creation

@ -0,0 +1,45 @@
properties:
content:
description: The content of this event. The fields in this object will vary depending
on the type of event.
title: EventContent
type: object
origin_server_ts:
description: Timestamp in milliseconds on originating homeserver when this event
was sent.
format: int64
type: integer
sender:
description: The MXID of the user who sent this event.
type: string
state_key:
description: Optional. This key will only be present for state events. A unique
key which defines the overwriting semantics for this piece of room state.
type: string
type:
description: The type of event.
type: string
unsigned:
description: Information about this event which was not sent by the originating
homeserver
properties:
age:
description: Time in milliseconds since the event was sent.
format: int64
type: integer
prev_content:
description: Optional. The previous ``content`` for this state. This will
be present only for state events appearing in the ``timeline``. If this
is not a state event, or there is no previous content, this key will be
missing.
title: EventContent
type: object
transaction_id:
description: Optional. The transaction ID set when this message was sent.
This key will only be present for message events sent by the device calling
this API.
type: string
title: Unsigned
type: object
title: Event
type: object

@ -0,0 +1,9 @@
properties:
events:
description: List of events
items:
allOf:
- $ref: event.yaml
type: object
type: array
type: object

@ -0,0 +1,34 @@
properties:
limit:
description: The maximum number of events to return.
type: integer
not_senders:
description: A list of sender IDs to exclude. If this list is absent then no senders
are excluded. A matching sender will be excluded even if it is listed in the
'senders' filter. A '*' can be used as a wildcard to match any sequence of characters.
items:
type: string
type: array
not_types:
description: A list of event types to exclude. If this list is absent then no
event types are excluded. A matching type will be excluded even if it is listed
in the 'types' filter. A '*' can be used as a wildcard to match any sequence
of characters.
items:
type: string
type: array
senders:
description: A list of senders IDs to include. If this list is absent then all
senders are included. A '*' can be used as a wildcard to match any sequence
of characters.
items:
type: string
type: array
types:
description: A list of event types to include. If this list is absent then all
event types are included. A '*' can be used as a wildcard to match any sequence
of characters.
items:
type: string
type: array
type: object

@ -0,0 +1,9 @@
properties:
kind:
enum:
- event_match
- profile_tag
- contains_display_name
- room_member_count
type: string
type: object

@ -0,0 +1,15 @@
properties:
actions:
items:
type:
- object
- string
type: array
default:
type: boolean
enabled:
type: boolean
rule_id:
type: string
title: PushRule
type: object

@ -0,0 +1,37 @@
properties:
content:
items:
allOf:
- $ref: push_rule.yaml
title: PushRule
type: object
type: array
override:
items:
allOf:
- $ref: push_rule.yaml
title: PushRule
type: object
type: array
room:
items:
allOf:
- $ref: push_rule.yaml
title: PushRule
type: object
type: array
sender:
items:
allOf:
- $ref: push_rule.yaml
title: PushRule
type: object
type: array
underride:
items:
allOf:
- $ref: push_rule.yaml
title: PushRule
type: object
type: array
type: object

@ -0,0 +1,17 @@
allOf:
- $ref: event_filter.yaml
properties:
not_rooms:
description: A list of room IDs to exclude. If this list is absent then no rooms
are excluded. A matching room will be excluded even if it is listed in the 'rooms'
filter. A '*' can be used as a wildcard to match any sequence of characters.
items:
type: string
type: array
rooms:
description: A list of room IDs to include. If this list is absent then all rooms
are included. A '*' can be used as a wildcard to match any sequence of characters.
items:
type: string
type: array
type: object

@ -0,0 +1,42 @@
properties:
event_fields:
description: List of event fields to include. If this list is absent then all
fields are included. The entries may include '.' charaters to indicate sub-fields.
So ['content.body'] will include the 'body' field of the 'content' object. A
literal '.' character in a field name may be escaped using a '\'. A server may
include more fields than were requested.
items:
type: string
type: array
event_format:
description: The format to use for events. 'client' will return the events in
a format suitable for clients. 'federation' will return the raw event as receieved
over federation. The default is 'client'.
enum:
- client
- federation
type: string
presence:
allOf:
- $ref: event_filter.yaml
description: The presence updates to include.
room:
properties:
ephemeral:
allOf:
- $ref: room_event_filter.yaml
description: The events that aren't recorded in the room history, e.g. typing
and receipts, to include for rooms.
include_leave:
description: Include rooms that the user has left in the sync, default false
type: boolean
state:
allOf:
- $ref: room_event_filter.yaml
description: The state events to include for rooms.
timeline:
allOf:
- $ref: room_event_filter.yaml
description: The message and state update events to include for rooms.
type: object
type: object

@ -0,0 +1,12 @@
allOf:
- $ref: event_batch.yaml
properties:
limited:
description: True if the number of events returned was limited by the ``limit``
on the filter
type: boolean
prev_batch:
description: If the batch was limited then this is a token that can be supplied
to the server to retrieve earlier events
type: string
type: object

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Directory API" title: "Matrix Client-Server Directory API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1/directory basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%/directory
consumes: consumes:
- application/json - application/json
produces: produces:
@ -29,6 +29,7 @@ paths:
name: roomAlias name: roomAlias
description: The room alias to set. description: The room alias to set.
required: true required: true
x-example: "#monkeys:matrix.org"
- in: body - in: body
name: roomInfo name: roomInfo
description: Information about this room alias. description: Information about this room alias.
@ -39,11 +40,20 @@ paths:
room_id: room_id:
type: string type: string
description: The room ID to set. description: The room ID to set.
example: |-
{
"room_id": "!abnjk1jdasj98:capuchins.com"
}
responses: responses:
200: 200:
description: The mapping was created. description: The mapping was created.
examples:
application/json: |-
{}
schema: schema:
type: object # empty json object type: object
tags:
- Room directory
get: get:
summary: Get the room ID corresponding to this room alias. summary: Get the room ID corresponding to this room alias.
parameters: parameters:
@ -52,6 +62,7 @@ paths:
name: roomAlias name: roomAlias
description: The room alias. description: The room alias.
required: true required: true
x-example: "#monkeys:matrix.org"
responses: responses:
200: 200:
description: The room ID and other information for this alias. description: The room ID and other information for this alias.
@ -67,10 +78,40 @@ paths:
items: items:
type: string type: string
description: A server which is aware of this room ID. description: A server which is aware of this room ID.
examples:
application/json: |-
{
"room_id": "!abnjk1jdasj98:capuchins.com",
"servers": [
"capuchins.com",
"matrix.org",
"another.com"
]
}
404: 404:
description: There is no mapped room ID for this room alias. description: There is no mapped room ID for this room alias.
examples:
application/json: |-
{
"errcode": "M_NOT_FOUND",
"error": "Room ID !abnjk1jdasj98:capuchins.com not found."
}
409:
description: A room alias with that name already exists.
examples:
application/json: |-
{
"errcode": "M_UNKNOWN",
"error": "Room alias #monkeys:matrix.org already exists."
}
tags:
- Room directory
delete: delete:
summary: Remove a mapping of room alias to room ID. summary: Remove a mapping of room alias to room ID.
description: |-
Remove a mapping of room alias to room ID.
Servers may choose to implement additional access control checks here, for instance that room aliases can only be deleted by their creator or a server administrator.
security: security:
- accessToken: [] - accessToken: []
parameters: parameters:
@ -79,9 +120,14 @@ paths:
name: roomAlias name: roomAlias
description: The room alias to remove. description: The room alias to remove.
required: true required: true
x-example: "#monkeys:matrix.org"
responses: responses:
200: 200:
description: The mapping was removed. description: The mapping was deleted.
examples:
application/json: |-
{}
schema: schema:
type: object # empty json object type: object
tags:
- Room directory

@ -1,11 +1,11 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v2 filter API" title: "Matrix Client-Server filter API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
basePath: /_matrix/client/v2_alpha basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -22,8 +22,8 @@ paths:
summary: Upload a new filter. summary: Upload a new filter.
description: |- description: |-
Uploads a new filter definition to the homeserver. Uploads a new filter definition to the homeserver.
Returns a filter ID that may be used in /sync requests to Returns a filter ID that may be used in future requests to
retrict which events are returned to the client. restrict which events are returned to the client.
security: security:
- accessToken: [] - accessToken: []
parameters: parameters:
@ -42,7 +42,7 @@ paths:
schema: schema:
type: object type: object
allOf: allOf:
- $ref: "definitions/sync_filter.json" - $ref: "definitions/sync_filter.yaml"
example: |- example: |-
{ {
"room": { "room": {
@ -56,7 +56,7 @@ paths:
"not_rooms": ["!726s6s6q:example.com"], "not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"] "not_senders": ["@spam:example.com"]
}, },
"emphemeral": { "ephemeral": {
"types": ["m.receipt", "m.typing"], "types": ["m.receipt", "m.typing"],
"not_rooms": ["!726s6s6q:example.com"], "not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"] "not_senders": ["@spam:example.com"]
@ -84,6 +84,8 @@ paths:
type: string type: string
description: |- description: |-
The ID of the filter that was created. The ID of the filter that was created.
tags:
- Room participation
"/user/{userId}/filter/{filterId}": "/user/{userId}/filter/{filterId}":
get: get:
summary: Download a filter summary: Download a filter
@ -120,7 +122,7 @@ paths:
"not_rooms": ["!726s6s6q:example.com"], "not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"] "not_senders": ["@spam:example.com"]
}, },
"emphemeral": { "ephemeral": {
"types": ["m.receipt", "m.typing"], "types": ["m.receipt", "m.typing"],
"not_rooms": ["!726s6s6q:example.com"], "not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"] "not_senders": ["@spam:example.com"]
@ -136,4 +138,6 @@ paths:
schema: schema:
type: object type: object
allOf: allOf:
- $ref: "definitions/sync_filter.json" - $ref: "definitions/sync_filter.yaml"
tags:
- Room participation

@ -0,0 +1,104 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Sync Guest API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/events":
get:
summary: Listen on the event stream.
description: |-
This will listen for new events related to a particular room and return
them to the caller. This will block until an event is received, or until
the ``timeout`` is reached.
This API is the same as the non-guest /events endpoint, but can be
called by guest users.
security:
- accessToken: []
parameters:
- in: query
type: string
name: from
description: |-
The token to stream from. This token is either from a previous
request to this API or from the initial sync API.
required: false
x-example: "s3456_9_0"
- in: query
type: integer
name: timeout
description: The maximum time in milliseconds to wait for an event.
required: false
x-example: "35000"
- in: query
type: array
items:
type: string
name: room_id
description: |-
The room IDs for which events should be returned.
x-example:
- "!somewhere:over"
- "!the:rainbow"
responses:
200:
description: "The events received, which may be none."
examples:
application/json: |-
{
"start": "s3456_9_0",
"end": "s3457_9_0",
"chunk": [
{
"age": 32,
"content": {
"body": "incoming message",
"msgtype": "m.text"
},
"event_id": "$14328055551tzaee:localhost",
"origin_server_ts": 1432804485886,
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"type": "m.room.message",
"sender": "@bob:localhost"
}
]
}
schema:
type: object
properties:
start:
type: string
description: |-
A token which correlates to the first value in ``chunk``. This
is usually the same token supplied to ``from=``.
end:
type: string
description: |-
A token which correlates to the last value in ``chunk``. This
token should be used in the next request to ``/events``.
chunk:
type: array
description: "An array of events."
items:
type: object
title: Event
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
400:
description: "Bad pagination ``from`` parameter."
# No tags to exclude this from the swagger UI - use the non-guest version instead.

@ -0,0 +1,92 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Room Joining API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
# With an extra " " to disambiguate from the 3pid invite endpoint
# The extra space makes it sort first for what I'm sure is a good reason.
"/rooms/{roomId}/invite ":
post:
summary: Invite a user to participate in a particular room.
description: |-
.. _invite-by-user-id-endpoint:
*Note that there are two forms of this API, which are documented separately.
This version of the API requires that the inviter knows the Matrix
identifier of the invitee. The other is documented in the*
`third party invites section`_.
This API invites a user to participate in a particular room.
They do not start participating in the room until they actually join the
room.
Only users currently in a particular room can invite other users to
join that room.
If the user was invited to the room, the homeserver will append a
``m.room.member`` event to the room.
.. _third party invites section: `invite-by-third-party-id-endpoint`_
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier (not alias) to which to invite the user.
required: true
x-example: "!d41d8cd:matrix.org"
- in: body
name: body
required: true
schema:
type: object
example: |-
{
"user_id": "@cheeky_monkey:matrix.org"
}
properties:
user_id:
type: string
description: The fully qualified user ID of the invitee.
required: ["user_id"]
responses:
200:
description: The user has been invited to join the room.
examples:
application/json: |-
{}
schema:
type: object
403:
description: |-
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
- The invitee has been banned from the room.
- The invitee is already a member of the room.
- The inviter is not currently in the room.
- The inviter's power level is insufficient to invite users to the room.
examples:
application/json: |-
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
tags:
- Room membership

@ -0,0 +1,70 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Room Inviting API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/join":
post:
summary: Start the requesting user participating in a particular room.
description: |-
This API starts a user participating in a particular room, if that user
is allowed to participate in that room. After this call, the client is
allowed to see all current state events in the room, and all subsequent
events associated with the room until the user leaves the room.
After a user has joined a room, the room will appear as an entry in the
response of the |initialSync| API.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier or room alias to join.
required: true
x-example: "#monkeys:matrix.org"
responses:
200:
description: |-
The room has been joined.
The joined room ID must be returned in the ``room_id`` field.
examples:
application/json: |-
{"room_id": "!d41d8cd:matrix.org"}
schema:
type: object
403:
description: |-
You do not have permission to join the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejection are:
- The room is invite-only and the user was not invited.
- The user has been banned from the room.
examples:
application/json: |-
{"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
x-alias:
canonical-link: "post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-join"
aliases:
- /_matrix/client/%CLIENT_MAJOR_VERSION%/join/{roomId}
tags:
- Room membership

@ -0,0 +1,96 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Room Leaving API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/leave":
post:
summary: Stop the requesting user participating in a particular room.
description: |-
This API stops a user participating in a particular room.
If the user was already in the room, they will no longer be able to see
new events in the room. If the room requires an invite to join, they
will need to be re-invited before they can re-join.
If the user was invited to the room, but had not joined, this call
serves to reject the invite.
The user will still be allowed to retrieve history from the room which
they were previously allowed to see.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier to leave.
required: true
x-example: "!nkl290a:matrix.org"
responses:
200:
description: |-
The room has been left.
examples:
application/json: |-
{}
schema:
type: object
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
tags:
- Room membership
"/rooms/{roomId}/forget":
post:
summary: Stop the requesting user remembering about a particular room.
description: |-
This API stops a user remembering about a particular room.
In general, history is a first class citizen in Matrix. After this API
is called, however, a user will no longer be able to retrieve history
for this room. If all users on a homeserver forget a room, the room is
eligible for deletion from that homeserver.
If the user is currently joined to the room, they will implicitly leave
the room as part of this API call.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier to forget.
required: true
x-example: "!au1ba7o:matrix.org"
responses:
200:
description: |-
The room has been forgotten.
examples:
application/json: |-
{}
schema:
type: object
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
tags:
- Room membership

@ -0,0 +1,99 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Room Creation API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
paths:
"/publicRooms":
get:
summary: Lists the public rooms on the server.
description: |-
Lists the public rooms on the server.
This API returns paginated responses.
responses:
200:
description: A list of the rooms on the server.
schema:
type: object
description: A list of the rooms on the server.
properties:
chunk:
title: "PublicRoomsChunks"
type: array
description: |-
A paginated chunk of public rooms.
items:
type: object
title: "PublicRoomsChunk"
properties:
aliases:
type: array
description: |-
Aliases of the room. May be empty.
items:
type: string
name:
type: string
description: |-
The name of the room, if any. May be null.
num_joined_members:
type: number
description: |-
The number of members joined to the room.
room_id:
type: string
description: |-
The ID of the room.
topic:
type: string
description: |-
The topic of the room, if any. May be null.
world_readable:
type: boolean
description: |-
Whether the room may be viewed by guest users without joining.
guest_can_join:
type: boolean
description: |-
Whether guest users may join the room and participate in it.
If they can, they will be subject to ordinary power level
rules like any other user.
start:
type: string
description: |-
A pagination token for the response.
end:
type: string
description: |-
A pagination token for the response.
examples:
application/json: |-
{
"chunk": [
{
"aliases": ["#murrays:cheese.bar"],
"guest_can_join": false,
"name": "CHEESE",
"num_joined_members": 37,
"room_id": "!ol19s:bleecker.street",
"topic": "Tasty tasty cheese",
"world_readable": true
}
],
"start": "p190q",
"end": "p1902"
}
400:
description: >
The request body is malformed or the room alias specified is already taken.
tags:
- Room discovery

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Registration and Login API" title: "Matrix Client-Server Registration and Login API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -81,7 +81,7 @@ paths:
(optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the /tokenrefresh API endpoint. (optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the /tokenrefresh API endpoint.
home_server: home_server:
type: string type: string
description: The hostname of the Home Server on which the account has been registered. description: The hostname of the homeserver on which the account has been registered.
400: 400:
description: |- description: |-
Part of the request was invalid. For example, the login type may not be recognised. Part of the request was invalid. For example, the login type may not be recognised.
@ -101,6 +101,8 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Session management
"/tokenrefresh": "/tokenrefresh":
post: post:
summary: Exchanges a refresh token for an access token. summary: Exchanges a refresh token for an access token.
@ -158,3 +160,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Session management

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Rooms API" title: "Matrix Client-Server Rooms API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -129,3 +129,5 @@ paths:
403: 403:
description: > description: >
You aren't a member of the room. You aren't a member of the room.
tags:
- Room participation

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Sync API" title: "Matrix Client-Server Sync API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -60,7 +60,7 @@ paths:
"origin_server_ts": 1432804485886, "origin_server_ts": 1432804485886,
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"type": "m.room.message", "type": "m.room.message",
"user_id": "@bob:localhost" "sender": "@bob:localhost"
} }
] ]
} }
@ -84,9 +84,11 @@ paths:
type: object type: object
title: Event title: Event
allOf: allOf:
- "$ref": "core-event-schema/room_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
400: 400:
description: "Bad pagination ``from`` parameter." description: "Bad pagination ``from`` parameter."
tags:
- Room participation
"/initialSync": "/initialSync":
get: get:
summary: Get the user's current state. summary: Get the user's current state.
@ -131,6 +133,14 @@ paths:
"type": "m.presence" "type": "m.presence"
} }
], ],
"account_data": [
{
"type": "org.example.custom.config",
"content": {
"custom_config_key": "custom_config_value"
}
}
],
"rooms": [ "rooms": [
{ {
"membership": "join", "membership": "join",
@ -146,7 +156,7 @@ paths:
"origin_server_ts": 1432804485886, "origin_server_ts": 1432804485886,
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"type": "m.room.message", "type": "m.room.message",
"user_id": "@alice:localhost" "sender": "@alice:localhost"
}, },
{ {
"age": 343511809, "age": 343511809,
@ -158,7 +168,7 @@ paths:
"origin_server_ts": 1432804487480, "origin_server_ts": 1432804487480,
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"type": "m.room.message", "type": "m.room.message",
"user_id": "@bob:localhost" "sender": "@bob:localhost"
} }
], ],
"end": "s3456_9_0", "end": "s3456_9_0",
@ -176,13 +186,12 @@ paths:
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"state_key": "", "state_key": "",
"type": "m.room.join_rules", "type": "m.room.join_rules",
"user_id": "@alice:localhost" "sender": "@alice:localhost"
}, },
{ {
"age": 6547561012, "age": 6547561012,
"content": { "content": {
"avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto", "avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto",
"displayname": null,
"membership": "join" "membership": "join"
}, },
"event_id": "$1426600438280zExKY:localhost", "event_id": "$1426600438280zExKY:localhost",
@ -191,7 +200,7 @@ paths:
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"state_key": "@alice:localhost", "state_key": "@alice:localhost",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@alice:localhost" "sender": "@alice:localhost"
}, },
{ {
"age": 7148267200, "age": 7148267200,
@ -203,7 +212,7 @@ paths:
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"state_key": "", "state_key": "",
"type": "m.room.create", "type": "m.room.create",
"user_id": "@alice:localhost" "sender": "@alice:localhost"
}, },
{ {
"age": 1622568720, "age": 1622568720,
@ -218,7 +227,7 @@ paths:
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"state_key": "@bob:localhost", "state_key": "@bob:localhost",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@bob:localhost" "sender": "@bob:localhost"
}, },
{ {
"age": 7148267004, "age": 7148267004,
@ -242,10 +251,22 @@ paths:
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"state_key": "", "state_key": "",
"type": "m.room.power_levels", "type": "m.room.power_levels",
"user_id": "@alice:localhost" "sender": "@alice:localhost"
} }
], ],
"visibility": "private" "visibility": "private",
"account_data": [
{
"type": "m.tag",
"content": {"tags": {"work": {"order": 1}}}
},
{
"type": "org.example.custom.room.config",
"content": {
"custom_config_key": "custom_config_value"
}
}
]
} }
] ]
} }
@ -265,7 +286,7 @@ paths:
type: object type: object
title: Event title: Event
allOf: allOf:
- "$ref": "core-event-schema/event.json" - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
rooms: rooms:
type: array type: array
items: items:
@ -284,7 +305,7 @@ paths:
title: "InviteEvent" title: "InviteEvent"
description: "The invite event if ``membership`` is ``invite``" description: "The invite event if ``membership`` is ``invite``"
allOf: allOf:
- "$ref": "v1-event-schema/m.room.member" - "$ref": "../../event-schemas/schema/m.room.member"
messages: messages:
type: object type: object
title: PaginationChunk title: PaginationChunk
@ -312,7 +333,7 @@ paths:
type: object type: object
title: RoomEvent title: RoomEvent
allOf: allOf:
- "$ref": "core-event-schema/room_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
required: ["start", "end", "chunk"] required: ["start", "end", "chunk"]
state: state:
type: array type: array
@ -325,17 +346,29 @@ paths:
title: StateEvent title: StateEvent
type: object type: object
allOf: allOf:
- "$ref": "core-event-schema/state_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
visibility: visibility:
type: string type: string
enum: ["private", "public"] enum: ["private", "public"]
description: |- description: |-
Whether this room is visible to the ``/publicRooms`` API Whether this room is visible to the ``/publicRooms`` API
or not." or not."
account_data:
type: array
description: |-
The private data that this user has attached to
this room.
items:
title: Event
type: object
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
required: ["room_id", "membership"] required: ["room_id", "membership"]
required: ["end", "rooms", "presence"] required: ["end", "rooms", "presence"]
404: 404:
description: There is no avatar URL for this user or this user does not exist. description: There is no avatar URL for this user or this user does not exist.
tags:
- Room participation
"/events/{eventId}": "/events/{eventId}":
get: get:
summary: Get a single event by event ID. summary: Get a single event by event ID.
@ -362,12 +395,14 @@ paths:
"msgtype": "m.text" "msgtype": "m.text"
}, },
"room_id:": "!wfgy43Sg4a:matrix.org", "room_id:": "!wfgy43Sg4a:matrix.org",
"user_id": "@bob:matrix.org", "sender": "@bob:matrix.org",
"event_id": "$asfDuShaf7Gafaw:matrix.org", "event_id": "$asfDuShaf7Gafaw:matrix.org",
"type": "m.room.message" "type": "m.room.message"
} }
schema: schema:
allOf: allOf:
- "$ref": "core-event-schema/event.json" - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
404: 404:
description: The event was not found or you do not have permission to read this event. description: The event was not found or you do not have permission to read this event.
tags:
- Room participation

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Presence API" title: "Matrix Client-Server Presence API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -67,6 +67,8 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Presence
get: get:
summary: Get this user's presence state. summary: Get this user's presence state.
description: |- description: |-
@ -85,8 +87,7 @@ paths:
application/json: |- application/json: |-
{ {
"presence": "unavailable", "presence": "unavailable",
"last_active_ago": 420845, "last_active_ago": 420845
"status_msg": null
} }
schema: schema:
type: object type: object
@ -107,6 +108,8 @@ paths:
description: |- description: |-
There is no presence state for this user. This user may not exist or There is no presence state for this user. This user may not exist or
isn't exposing presence information to you. isn't exposing presence information to you.
tags:
- Presence
"/presence/list/{userId}": "/presence/list/{userId}":
post: post:
summary: Add or remove users from this presence list. summary: Add or remove users from this presence list.
@ -161,6 +164,8 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Presence
get: get:
summary: Get presence events for this presence list. summary: Get presence events for this presence list.
description: |- description: |-
@ -205,4 +210,6 @@ paths:
type: object type: object
title: PresenceEvent title: PresenceEvent
allOf: allOf:
- "$ref": "core-event-schema/event.json" - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
tags:
- Presence

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Profile API" title: "Matrix Client-Server Profile API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -59,6 +59,8 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- User data
get: get:
summary: Get the user's display name. summary: Get the user's display name.
description: |- description: |-
@ -88,6 +90,8 @@ paths:
description: The user's display name if they have set one. description: The user's display name if they have set one.
404: 404:
description: There is no display name for this user or this user does not exist. description: There is no display name for this user or this user does not exist.
tags:
- User data
"/profile/{userId}/avatar_url": "/profile/{userId}/avatar_url":
put: put:
summary: Set the user's avatar URL. summary: Set the user's avatar URL.
@ -129,6 +133,8 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- User data
get: get:
summary: Get the user's avatar URL. summary: Get the user's avatar URL.
description: |- description: |-
@ -158,6 +164,8 @@ paths:
description: The user's avatar URL if they have set one. description: The user's avatar URL if they have set one.
404: 404:
description: There is no avatar URL for this user or this user does not exist. description: There is no avatar URL for this user or this user does not exist.
tags:
- User data
"/profile/{userId}": "/profile/{userId}":
get: get:
summary: Get this user's profile information. summary: Get this user's profile information.
@ -192,4 +200,6 @@ paths:
type: string type: string
description: The user's display name if they have set one. description: The user's display name if they have set one.
404: 404:
description: There is no profile information for this user or this user does not exist. description: There is no profile information for this user or this user does not exist.
tags:
- User data

@ -6,7 +6,7 @@ host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/push/v1 basePath: /_matrix/push/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -189,4 +189,5 @@ paths:
items: items:
type: string type: string
description: A pushkey description: A pushkey
tags:
- Push notifications

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Push API" title: "Matrix Client-Server Push API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -60,7 +60,6 @@ paths:
Max length, 512 bytes. Max length, 512 bytes.
kind: kind:
type: string type: string
enum: ["http", null]
description: |- description: |-
The kind of pusher to configure. ``"http"`` makes a pusher that The kind of pusher to configure. ``"http"`` makes a pusher that
sends HTTP pokes. ``null`` deletes the pusher. sends HTTP pokes. ``null`` deletes the pusher.
@ -114,7 +113,7 @@ paths:
description: |- description: |-
If true, the homeserver should add another pusher with the If true, the homeserver should add another pusher with the
given pushkey and App ID in addition to any others with given pushkey and App ID in addition to any others with
different user IDs. Otherwise, the Home Server must remove any different user IDs. Otherwise, the homeserver must remove any
other pushers with the same App ID and pushkey for different other pushers with the same App ID and pushkey for different
users. The default is ``false``. users. The default is ``false``.
required: ['profile_tag', 'kind', 'app_id', 'app_display_name', required: ['profile_tag', 'kind', 'app_id', 'app_display_name',
@ -141,4 +140,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Push notifications

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Push Rules API" title: "Matrix Client-Server Push Rules API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -45,14 +45,14 @@ paths:
description: The ruleset for this profile tag. description: The ruleset for this profile tag.
title: Ruleset title: Ruleset
allOf: [ allOf: [
"$ref": "definitions/push_ruleset.json" "$ref": "definitions/push_ruleset.yaml"
] ]
global: global:
type: object type: object
description: The global ruleset. description: The global ruleset.
title: Ruleset title: Ruleset
allOf: [ allOf: [
"$ref": "definitions/push_ruleset.json" "$ref": "definitions/push_ruleset.yaml"
] ]
examples: examples:
application/json: |- application/json: |-
@ -245,6 +245,8 @@ paths:
] ]
} }
} }
tags:
- Push notifications
"/pushrules/{scope}/{kind}/{ruleId}": "/pushrules/{scope}/{kind}/{ruleId}":
get: get:
summary: Retrieve a push rule. summary: Retrieve a push rule.
@ -295,8 +297,10 @@ paths:
description: The push rule. description: The push rule.
title: PushRule title: PushRule
allOf: [ allOf: [
"$ref": "definitions/push_rule.json" "$ref": "definitions/push_rule.yaml"
] ]
tags:
- Push notifications
delete: delete:
summary: Delete a push rule. summary: Delete a push rule.
description: |- description: |-
@ -335,6 +339,8 @@ paths:
{} {}
schema: schema:
type: object # empty json object type: object # empty json object
tags:
- Push notifications
put: put:
summary: Add or change a push rule. summary: Add or change a push rule.
description: |- description: |-
@ -414,7 +420,7 @@ paths:
items: items:
type: object type: object
title: conditions title: conditions
allOf: [ "$ref": "definitions/push_condition.json" ] allOf: [ "$ref": "definitions/push_condition.yaml" ]
required: ["actions"] required: ["actions"]
responses: responses:
200: 200:
@ -438,6 +444,8 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Push notifications
"/pushrules/{scope}/{kind}/{ruleId}/enabled": "/pushrules/{scope}/{kind}/{ruleId}/enabled":
put: put:
summary: "Enable or disable a push rule." summary: "Enable or disable a push rule."
@ -470,14 +478,21 @@ paths:
description: | description: |
The identifier for the rule. The identifier for the rule.
- in: body - in: body
name: <body> name: body
description: | description: |
Whether the push rule is enabled or not. Whether the push rule is enabled or not.
required: true required: true
schema: schema:
type: boolean type: object
properties:
enabled:
type: boolean
description: Whether the push rule is enabled or not.
required: ["enabled"]
example: |- example: |-
true {
"enabled": true
}
responses: responses:
200: 200:
description: The push rule was enabled or disabled. description: The push rule was enabled or disabled.
@ -485,4 +500,6 @@ paths:
application/json: |- application/json: |-
{} {}
schema: schema:
type: object # empty json object type: object
tags:
- Push notifications

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v2 Receipts API" title: "Matrix Client-Server Receipts API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/v2_alpha basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -67,3 +67,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Room participation

@ -0,0 +1,84 @@
swagger: '2.0'
info:
title: "Matrix Client-Server message redaction API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/api/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/redact/{eventId}/{txnId}":
put:
summary: Strips all non-integrity-critical information out of an event.
description: |-
Strips all information out of an event which isn't critical to the
integrity of the server-side representation of the room.
This cannot be undone.
Users may redact their own events, and any user with a power level
greater than or equal to the `redact` power level of the room may
redact events there.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room from which to redact the event.
required: true
x-example: "!637q39766251:example.com"
- in: path
type: string
name: eventId
description: The ID of the event to redact
required: true
x-example: "bai2b1i9:matrix.org"
- in: path
name: txnId
type: string
description: |-
The transaction ID for this event. Clients should generate a
unique ID; it will be used by the server to ensure idempotency of requests.
required: true
x-example: "37"
- in: body
name: body
schema:
type: object
example: |-
{
"reason": "Indecent material"
}
properties:
reason:
type: string
description: The reason for the event being redacted.
responses:
200:
description: "An ID for the redaction event."
examples:
application/json: |-
{
"event_id": "YUwQidLecu"
}
schema:
type: object
properties:
event_id:
type: string
description: |-
A unique identifier for the event.
tags:
- Room participation

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v2 Registration API" title: "Matrix Client-Server Registration API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v2_alpha basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -17,7 +17,24 @@ paths:
summary: Register for an account on this homeserver. summary: Register for an account on this homeserver.
description: |- description: |-
Register for an account on this homeserver. Register for an account on this homeserver.
There are two kinds of user account:
- `user` accounts. These accounts may use the full API described in this specification.
- `guest` accounts. These accounts may have limited permissions and may not be supported by all servers.
parameters: parameters:
- in: query
name: kind
type: string
x-example: guest
required: false
default: user
enum:
- guest
- user
description: The kind of account to register. Defaults to `user`.
- in: body - in: body
name: body name: body
schema: schema:
@ -77,7 +94,7 @@ paths:
(optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the /tokenrefresh API endpoint. (optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the /tokenrefresh API endpoint.
home_server: home_server:
type: string type: string
description: The hostname of the Home Server on which the account has been registered. description: The hostname of the homeserver on which the account has been registered.
400: 400:
description: |- description: |-
Part of the request was invalid. This may include one of the following error codes: Part of the request was invalid. This may include one of the following error codes:
@ -90,7 +107,7 @@ paths:
including after authentication if the requested user ID was registered including after authentication if the requested user ID was registered
whilst the client was performing authentication. whilst the client was performing authentication.
Home Servers MUST perform the relevant checks and return these codes before Homeservers MUST perform the relevant checks and return these codes before
performing `User-Interactive Authentication`_, although they may also return performing `User-Interactive Authentication`_, although they may also return
them after authentication is completed if, for example, the requested user ID them after authentication is completed if, for example, the requested user ID
was registered whilst the client was performing authentication. was registered whilst the client was performing authentication.
@ -104,3 +121,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- User data

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 state event send API" title: "Matrix Client-Server message event send API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -18,29 +18,24 @@ securityDefinitions:
name: access_token name: access_token
in: query in: query
paths: paths:
"/rooms/{roomId}/state/{eventType}/{stateKey}": "/rooms/{roomId}/send/{eventType}/{txnId}":
put: put:
summary: Send a message event to the given room. summary: Send a message event to the given room.
description: | description: |-
State events can be sent using this endpoint. These events will be This endpoint is used to send a message event to a room. Message events
overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all allow access to historical events and pagination, making them suited
match. If the state event has an empty ``state_key``, it can be for "once-off" activity in a room.
omitted from the path.
Requests to this endpoint **cannot use transaction IDs**
like other ``PUT`` paths because they cannot be differentiated from the
``state_key``. Furthermore, ``POST`` is unsupported on state paths.
The body of the request should be the content object of the event; the The body of the request should be the content object of the event; the
fields in this object will vary depending on the type of event. See fields in this object will vary depending on the type of event. See
`Room Events`_ for the ``m.`` event specification. `Room Events`_ for the m. event specification.
security: security:
- accessToken: [] - accessToken: []
parameters: parameters:
- in: path - in: path
type: string type: string
name: roomId name: roomId
description: The room to set the state in description: The room to send the event to.
required: true required: true
x-example: "!636q39766251:example.com" x-example: "!636q39766251:example.com"
- in: path - in: path
@ -48,20 +43,23 @@ paths:
name: eventType name: eventType
description: The type of event to send. description: The type of event to send.
required: true required: true
x-example: "m.room.name" x-example: "m.room.message"
- in: path - in: path
name: txnId
type: string type: string
name: stateKey description: |-
description: The state_key for the state to send. Defaults to the empty string. The transaction ID for this event. Clients should generate a
unique ID; it will be used by the server to ensure idempotency of requests.
required: true required: true
x-example: "" x-example: "35"
- in: body - in: body
name: body name: body
schema: schema:
type: object type: object
example: |- example: |-
{ {
"name": "New name for the room" "msgtype": "m.text",
"body": "hello"
} }
responses: responses:
200: 200:
@ -78,3 +76,5 @@ paths:
type: string type: string
description: |- description: |-
A unique identifier for the event. A unique identifier for the event.
tags:
- Room participation

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 message event send API" title: "Matrix Client-Server state event send API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -18,24 +18,29 @@ securityDefinitions:
name: access_token name: access_token
in: query in: query
paths: paths:
"/rooms/{roomId}/send/{eventType}/{txnId}": "/rooms/{roomId}/state/{eventType}/{stateKey}":
put: put:
summary: Send a message event to the given room. summary: Send a state event to the given room.
description: |- description: |
This endpoint is used to send a message event to a room. Message events State events can be sent using this endpoint. This endpoint is
allow access to historical events and pagination, making them suited equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}`
for "once-off" activity in a room. with an empty `stateKey`. Previous state events with matching
`<roomId>` and `<eventType>`, and empty `<stateKey>`, will be overwritten.
Requests to this endpoint **cannot use transaction IDs**
like other ``PUT`` paths because they cannot be differentiated from the
``state_key``. Furthermore, ``POST`` is unsupported on state paths.
The body of the request should be the content object of the event; the The body of the request should be the content object of the event; the
fields in this object will vary depending on the type of event. See fields in this object will vary depending on the type of event. See
`Room Events`_ for the m. event specification. `Room Events`_ for the ``m.`` event specification.
security: security:
- accessToken: [] - accessToken: []
parameters: parameters:
- in: path - in: path
type: string type: string
name: roomId name: roomId
description: The room to send the event to. description: The room to set the state in
required: true required: true
x-example: "!636q39766251:example.com" x-example: "!636q39766251:example.com"
- in: path - in: path
@ -43,23 +48,20 @@ paths:
name: eventType name: eventType
description: The type of event to send. description: The type of event to send.
required: true required: true
x-example: "m.room.message" x-example: "m.room.name"
- in: path - in: path
name: txnId
type: string type: string
description: |- name: stateKey
The transaction ID for this event. Clients should generate a description: The state_key for the state to send. Defaults to the empty string.
unique ID; it will be used by the server to ensure idempotency of requests.
required: true required: true
x-example: "35" x-example: ""
- in: body - in: body
name: body name: body
schema: schema:
type: object type: object
example: |- example: |-
{ {
"msgtype": "m.text", "name": "New name for the room"
"body": "hello"
} }
responses: responses:
200: 200:
@ -76,21 +78,30 @@ paths:
type: string type: string
description: |- description: |-
A unique identifier for the event. A unique identifier for the event.
"/rooms/{roomId}/send/{eventType}": tags:
post: - Room participation
summary: Send a message event to the given room. "/rooms/{roomId}/state/{eventType}":
description: |- put:
This endpoint can be used to send a message event to a room; however summary: Send a state event to the given room.
the lack of a transaction ID means that it is possible to cause message description: |
duplication if events are resent on error, so it is preferable to use State events can be sent using this endpoint. These events will be
`PUT /_matrix/client/api/v1/rooms/{roomId}/send/{eventType}/{txnId}`_. overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all
match. This endpoint forces the state key to be the empty string.
Requests to this endpoint **cannot use transaction IDs**
like other ``PUT`` paths because they cannot be differentiated from the
``state_key``. Furthermore, ``POST`` is unsupported on state paths.
The body of the request should be the content object of the event; the
fields in this object will vary depending on the type of event. See
`Room Events`_ for the ``m.`` event specification.
security: security:
- accessToken: [] - accessToken: []
parameters: parameters:
- in: path - in: path
type: string type: string
name: roomId name: roomId
description: The room to send the event to. description: The room to set the state in
required: true required: true
x-example: "!636q39766251:example.com" x-example: "!636q39766251:example.com"
- in: path - in: path
@ -98,15 +109,14 @@ paths:
name: eventType name: eventType
description: The type of event to send. description: The type of event to send.
required: true required: true
x-example: "m.room.message" x-example: "m.room.name"
- in: body - in: body
name: body name: body
schema: schema:
type: object type: object
example: |- example: |-
{ {
"msgtype": "m.text", "name": "New name for the room"
"body": "hello"
} }
responses: responses:
200: 200:
@ -123,3 +133,5 @@ paths:
type: string type: string
description: |- description: |-
A unique identifier for the event. A unique identifier for the event.
tags:
- Room participation

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Rooms API" title: "Matrix Client-Server Rooms API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -44,7 +44,7 @@ paths:
- in: path - in: path
type: string type: string
name: stateKey name: stateKey
description: The key of the state to look up. Defaults to the empty string. description: The key of the state to look up.
required: true required: true
x-example: "" x-example: ""
responses: responses:
@ -61,7 +61,49 @@ paths:
description: > description: >
You aren't a member of the room and weren't previously a You aren't a member of the room and weren't previously a
member of the room. member of the room.
tags:
- Room participation
"/rooms/{roomId}/state/{eventType}":
get:
summary: Get the state identified by the type, with the empty state key.
description: |-
Looks up the contents of a state event in a room. If the user is
joined to the room then the state is taken from the current
state of the room. If the user has left the room then the state is
taken from the state of the room when they left.
This looks up the state event with the empty state key.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room to look up the state in.
required: true
x-example: "!636q39766251:example.com"
- in: path
type: string
name: eventType
description: The type of state to look up.
required: true
x-example: "m.room.name"
responses:
200:
description: The content of the state event.
examples:
application/json: |-
{"name": "Example room name"}
schema:
type: object
404:
description: The room has no state with the given type or key.
403:
description: >
You aren't a member of the room and weren't previously a
member of the room.
tags:
- Room participation
"/rooms/{roomId}/state": "/rooms/{roomId}/state":
get: get:
summary: Get all state events in the current state of a room. summary: Get all state events in the current state of a room.
@ -92,13 +134,12 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "", "state_key": "",
"type": "m.room.join_rules", "type": "m.room.join_rules",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 6547561012, "age": 6547561012,
"content": { "content": {
"avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto",
"displayname": null,
"membership": "join" "membership": "join"
}, },
"event_id": "$1426600438280zExKY:example.com", "event_id": "$1426600438280zExKY:example.com",
@ -107,7 +148,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "@alice:example.com", "state_key": "@alice:example.com",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 7148267200, "age": 7148267200,
@ -119,7 +160,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "", "state_key": "",
"type": "m.room.create", "type": "m.room.create",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 1622568720, "age": 1622568720,
@ -134,7 +175,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "@bob:example.com", "state_key": "@bob:example.com",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@bob:example.com" "sender": "@bob:example.com"
}, },
{ {
"age": 7148267004, "age": 7148267004,
@ -158,7 +199,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "", "state_key": "",
"type": "m.room.power_levels", "type": "m.room.power_levels",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
} }
] ]
schema: schema:
@ -173,12 +214,13 @@ paths:
title: StateEvent title: StateEvent
type: object type: object
allOf: allOf:
- "$ref": "core-event-schema/state_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
403: 403:
description: > description: >
You aren't a member of the room and weren't previously a You aren't a member of the room and weren't previously a
member of the room. member of the room.
tags:
- Room participation
"/rooms/{roomId}/initialSync": "/rooms/{roomId}/initialSync":
get: get:
summary: Snapshot the current state of a room and its most recent messages. summary: Snapshot the current state of a room and its most recent messages.
@ -212,7 +254,7 @@ paths:
"origin_server_ts": 1432804485886, "origin_server_ts": 1432804485886,
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"type": "m.room.message", "type": "m.room.message",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 343511809, "age": 343511809,
@ -224,7 +266,7 @@ paths:
"origin_server_ts": 1432804487480, "origin_server_ts": 1432804487480,
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"type": "m.room.message", "type": "m.room.message",
"user_id": "@bob:example.com" "sender": "@bob:example.com"
} }
], ],
"end": "s3456_9_0", "end": "s3456_9_0",
@ -242,13 +284,12 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "", "state_key": "",
"type": "m.room.join_rules", "type": "m.room.join_rules",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 6547561012, "age": 6547561012,
"content": { "content": {
"avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto",
"displayname": null,
"membership": "join" "membership": "join"
}, },
"event_id": "$1426600438280zExKY:example.com", "event_id": "$1426600438280zExKY:example.com",
@ -257,7 +298,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "@alice:example.com", "state_key": "@alice:example.com",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 7148267200, "age": 7148267200,
@ -269,7 +310,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "", "state_key": "",
"type": "m.room.create", "type": "m.room.create",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 1622568720, "age": 1622568720,
@ -284,7 +325,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "@bob:example.com", "state_key": "@bob:example.com",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@bob:example.com" "sender": "@bob:example.com"
}, },
{ {
"age": 7148267004, "age": 7148267004,
@ -308,10 +349,14 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "", "state_key": "",
"type": "m.room.power_levels", "type": "m.room.power_levels",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
} }
], ],
"visibility": "private" "visibility": "private",
"account_data": [{
"type": "m.tag",
"content": {"tags": {"work": {"order": "1"}}}
}]
} }
schema: schema:
title: RoomInfo title: RoomInfo
@ -351,7 +396,7 @@ paths:
type: object type: object
title: RoomEvent title: RoomEvent
allOf: allOf:
- "$ref": "core-event-schema/room_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
required: ["start", "end", "chunk"] required: ["start", "end", "chunk"]
state: state:
type: array type: array
@ -364,19 +409,29 @@ paths:
title: StateEvent title: StateEvent
type: object type: object
allOf: allOf:
- "$ref": "core-event-schema/state_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
visibility: visibility:
type: string type: string
enum: ["private", "public"] enum: ["private", "public"]
description: |- description: |-
Whether this room is visible to the ``/publicRooms`` API Whether this room is visible to the ``/publicRooms`` API
or not." or not."
required: ["room_id", "membership"] account_data:
type: array
description: |-
The private data that this user has attached to this room.
items:
title: Event
type: object
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
required: ["room_id"]
403: 403:
description: > description: >
You aren't a member of the room and weren't previously a You aren't a member of the room and weren't previously a
member of the room. member of the room.
tags:
- Room participation
"/rooms/{roomId}/members": "/rooms/{roomId}/members":
get: get:
summary: Get the m.room.member events for the room. summary: Get the m.room.member events for the room.
@ -403,7 +458,6 @@ paths:
"age": 6547561012, "age": 6547561012,
"content": { "content": {
"avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto",
"displayname": null,
"membership": "join" "membership": "join"
}, },
"event_id": "$1426600438280zExKY:example.com", "event_id": "$1426600438280zExKY:example.com",
@ -412,7 +466,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "@alice:example.com", "state_key": "@alice:example.com",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@alice:example.com" "sender": "@alice:example.com"
}, },
{ {
"age": 1622568720, "age": 1622568720,
@ -427,7 +481,7 @@ paths:
"room_id": "!636q39766251:example.com", "room_id": "!636q39766251:example.com",
"state_key": "@bob:example.com", "state_key": "@bob:example.com",
"type": "m.room.member", "type": "m.room.member",
"user_id": "@bob:example.com" "sender": "@bob:example.com"
} }
] ]
} }
@ -440,9 +494,10 @@ paths:
title: MemberEvent title: MemberEvent
type: object type: object
allOf: allOf:
- "$ref": "v1-event-schema/m.room.member" - "$ref": "../../event-schemas/schema/m.room.member"
403: 403:
description: > description: >
You aren't a member of the room and weren't previously a You aren't a member of the room and weren't previously a
member of the room. member of the room.
tags:
- Room participation

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Search API" title: "Matrix Client-Server Search API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -67,7 +67,7 @@ paths:
title: Filter title: Filter
description: |- description: |-
The filter to apply to search results. The filter to apply to search results.
This has the same format as v2 filter API. This has the same format as filter API.
required: ["search_term"] required: ["search_term"]
required: ["search_categories"] required: ["search_categories"]
responses: responses:
@ -111,7 +111,7 @@ paths:
title: Event title: Event
description: The event that matched. description: The event that matched.
allOf: allOf:
- "$ref": "core-event-schema/room_event.json" - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
examples: examples:
application/json: |- application/json: |-
{ {
@ -131,7 +131,7 @@ paths:
"origin_server_ts": 1444298308034, "origin_server_ts": 1444298308034,
"room_id": "!qPewotXpIctQySfjSy:localhost", "room_id": "!qPewotXpIctQySfjSy:localhost",
"type": "m.room.message", "type": "m.room.message",
"user_id": "@test:localhost" "sender": "@test:localhost"
} }
} }
} }
@ -144,3 +144,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Search

@ -1,11 +1,11 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v2 sync API" title: "Matrix Client-Server sync API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
basePath: /_matrix/client/v2_alpha basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -95,33 +95,26 @@ paths:
description: |- description: |-
Updates to rooms. Updates to rooms.
properties: properties:
joined: join:
title: Joined title: Joined Rooms
type: object type: object
description: |-
The rooms that the user has joined.
additionalProperties: additionalProperties:
title: Joined Room title: Joined Room
type: object type: object
properties: properties:
event_map:
title: EventMap
type: object
description: |-
A map from event ID to events for this room. The
events are referenced from the ``timeline`` and
``state`` keys for this room.
additionalProperties:
title: Event
description: An event object.
type: object
allOf:
- $ref: "core-event-schema/event.json"
state: state:
title: State title: State
type: object type: object
description: |- description: |-
The state updates for the room. Updates to the state, between the time indicated by
the ``since`` parameter, and the start of the
``timeline`` (or all state up to the start of the
``timeline``, if ``since`` is not given, or
``full_state`` is true).
allOf: allOf:
- $ref: "definitions/room_event_batch.json" - $ref: "definitions/event_batch.yaml"
timeline: timeline:
title: Timeline title: Timeline
type: object type: object
@ -129,7 +122,7 @@ paths:
The timeline of messages and state changes in the The timeline of messages and state changes in the
room. room.
allOf: allOf:
- $ref: "definitions/timeline_batch.json" - $ref: "definitions/timeline_batch.yaml"
ephemeral: ephemeral:
title: Ephemeral title: Ephemeral
type: object type: object
@ -138,9 +131,17 @@ paths:
recorded in the timeline or state of the room. recorded in the timeline or state of the room.
e.g. typing. e.g. typing.
allOf: allOf:
- $ref: "definitions/event_batch.json" - $ref: "definitions/event_batch.yaml"
invited: account_data:
title: Invited title: Account Data
type: object
description: |-
The private data that this user has attached to
this room.
allOf:
- $ref: "definitions/event_batch.yaml"
invite:
title: Invited Rooms
type: object type: object
description: |- description: |-
The rooms that the user has been invited to. The rooms that the user has been invited to.
@ -165,38 +166,23 @@ paths:
delta against the archived ``state`` not the delta against the archived ``state`` not the
``invite_state``. ``invite_state``.
allOf: allOf:
- $ref: "definitions/event_batch.json" - $ref: "definitions/event_batch.yaml"
archived: leave:
title: Archived title: Left rooms
type: object type: object
description: |- description: |-
The rooms that the user has left or been banned from. The The rooms that the user has left or been banned from.
entries in the room_map will lack an ``ephemeral`` key.
additionalProperties: additionalProperties:
title: Archived Room title: Left Room
type: object type: object
properties: properties:
event_map:
title: EventMap
type: object
description: |-
A map from event ID to events for this room. The
events are referenced from the ``timeline`` and
``state`` keys for this room.
additionalProperties:
title: Event
description: An event object.
type: object
allOf:
- $ref: "core-event-schema/event.json"
state: state:
title: State title: State
type: object type: object
description: |- description: |-
The state updates for the room up to the point when The state updates for the room up to the start of the timeline.
the user left.
allOf: allOf:
- $ref: "definitions/room_event_batch.json" - $ref: "definitions/event_batch.yaml"
timeline: timeline:
title: Timeline title: Timeline
type: object type: object
@ -204,14 +190,14 @@ paths:
The timeline of messages and state changes in the The timeline of messages and state changes in the
room up to the point when the user left. room up to the point when the user left.
allOf: allOf:
- $ref: "definitions/timeline_batch.json" - $ref: "definitions/timeline_batch.yaml"
presence: presence:
title: Presence title: Presence
type: object type: object
description: |- description: |-
The updates to the presence status of other users. The updates to the presence status of other users.
allOf: allOf:
- $ref: "definitions/event_batch.json" - $ref: "definitions/event_batch.yaml"
examples: examples:
application/json: |- application/json: |-
{ {
@ -225,45 +211,54 @@ paths:
} }
] ]
}, },
"account_data": {
"events": [
{
"type": "org.example.custom.config",
"content": {
"custom_config_key": "custom_config_value"
}
}
]
},
"rooms": { "rooms": {
"joined": { "join": {
"!726s6s6q:example.com": { "!726s6s6q:example.com": {
"event_map": {
"$66697273743031:example.com": {
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@alice:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795
},
"$7365636s6r6432:example.com": {
"sender": "@bob:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795
},
"$74686972643033:example.com": {
"sender": "@alice:example.com",
"type": "m.room.message",
"unsigned": {"age": "124524", "txn_id": "1234"},
"content": {
"body": "I am a fish",
"msgtype": "m.text"
},
"origin_server_ts": 1417731086797
}
},
"state": { "state": {
"events": [ "events": [
"$66697273743031:example.com", {
"$7365636s6r6432:example.com" "sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@alice:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795,
"event_id": "$66697273743031:example.com"
}
] ]
}, },
"timeline": { "timeline": {
"events": [ "events": [
"$7365636s6r6432:example.com", {
"$74686972643033:example.com" "sender": "@bob:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "join"},
"prev_content": {"membership": "invite"},
"origin_server_ts": 1417731086795,
"event_id": "$7365636s6r6432:example.com"
},
{
"sender": "@alice:example.com",
"type": "m.room.message",
"age": 124524,
"txn_id": "1234",
"content": {
"body": "I am a fish",
"msgtype": "m.text"
},
"origin_server_ts": 1417731086797,
"event_id": "$74686972643033:example.com"
}
], ],
"limited": true, "limited": true,
"prev_batch": "t34-23535_0_0" "prev_batch": "t34-23535_0_0"
@ -271,15 +266,28 @@ paths:
"ephemeral": { "ephemeral": {
"events": [ "events": [
{ {
"room_id": "!726s6s6q:example.com",
"type": "m.typing", "type": "m.typing",
"content": {"user_ids": ["@alice:example.com"]} "content": {"user_ids": ["@alice:example.com"]}
} }
] ]
},
"account_data": {
"events": [
{
"type": "m.tag",
"content": {"tags": {"work": {"order": 1}}}
},
{
"type": "org.example.custom.room.config",
"content": {
"custom_config_key": "custom_config_value"
}
}
]
} }
} }
}, },
"invited": { "invite": {
"!696r7674:example.com": { "!696r7674:example.com": {
"invite_state": { "invite_state": {
"events": [ "events": [
@ -299,6 +307,8 @@ paths:
} }
} }
}, },
"archived": {} "leave": {}
} }
} }
tags:
- Room participation

@ -0,0 +1,153 @@
swagger: '2.0'
info:
title: "Matrix Client-Server tag API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/user/{userId}/rooms/{roomId}/tags":
get:
summary: List the tags for a room.
description: |-
List the tags set by a user on a room.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
required: true
description: |-
The id of the user to get tags for. The access token must be
authorized to make requests for this user id.
x-example: "@alice:example.com"
- in: path
type: string
name: roomId
required: true
description: |-
The id of the room to get tags for.
x-example: "!726s6s6q:example.com"
responses:
200:
description:
The list of tags for the user for the room.
schema:
type: object
properties:
tags:
title: Tags
type: object
examples:
application/json: |-
{
"tags": {
"work": {"order": "1"},
"pinned": {}
}
}
tags:
- User data
"/user/{userId}/rooms/{roomId}/tags/{tag}":
put:
summary: Add a tag to a room.
description: |-
Add a tag to the room.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
required: true
description: |-
The id of the user to add a tag for. The access token must be
authorized to make requests for this user id.
x-example: "@alice:example.com"
- in: path
type: string
name: roomId
required: true
description: |-
The id of the room to add a tag to.
x-example: "!726s6s6q:example.com"
- in: path
type: string
name: tag
required: true
description: |-
The tag to add.
x-example: "work"
- in: body
name: body
required: true
description: |-
Extra data for the tag, e.g. ordering.
schema:
type: object
example: |-
{"order": "1"}
responses:
200:
description:
The tag was successfully added.
schema:
type: object
examples:
application/json: |-
{}
tags:
- User data
delete:
summary: Remove a tag from the room.
description: |-
Remove a tag from the room.
security:
- access_token: []
parameters:
- in: path
type: string
name: userId
required: true
description: |-
The id of the user to remove a tag for. The access token must be
authorized to make requests for this user id.
x-example: "@alice:example.com"
- in: path
type: string
name: roomId
required: true
description: |-
The id of the room to remove a tag from.
x-example: "!726s6s6q:example.com"
- in: path
type: string
name: tag
required: true
description: |-
The tag to remove.
x-example: "work"
responses:
200:
description:
The tag was successfully removed
schema:
type: object
examples:
application/json: |-
{}
tags:
- User data

@ -0,0 +1,125 @@
swagger: '2.0'
info:
title: "Matrix Client-Server Room Membership API for third party identifiers"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/invite":
post:
summary: Invite a user to participate in a particular room.
description: |-
.. _invite-by-third-party-id-endpoint:
*Note that there are two forms of this API, which are documented separately.
This version of the API does not require that the inviter know the Matrix
identifier of the invitee, and instead relies on third party identifiers.
The homeserver uses an identity server to perform the mapping from
third party identifier to a Matrix identifier. The other is documented in the*
`joining rooms section`_.
This API invites a user to participate in a particular room.
They do not start participating in the room until they actually join the
room.
Only users currently in a particular room can invite other users to
join that room.
If the identity server did know the Matrix user identifier for the
third party identifier, the homeserver will append a ``m.room.member``
event to the room.
If the identity server does not know a Matrix user identifier for the
passed third party identifier, the homeserver will issue an invitation
which can be accepted upon providing proof of ownership of the third
party identifier. This is achieved by the identity server generating a
token, which it gives to the inviting homeserver. The homeserver will
add an ``m.room.third_party_invite`` event into the graph for the room,
containing that token.
When the invitee binds the invited third party identifier to a Matrix
user ID, the identity server will give the user a list of pending
invitations, each containing:
- The room ID to which they were invited
- The token given to the homeserver
- A signature of the token, signed with the identity server's private key
- The matrix user ID who invited them to the room
If a token is requested from the identity server, the homeserver will
append a ``m.room.third_party_invite`` event to the room.
.. _joining rooms section: `invite-by-user-id-endpoint`_
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier (not alias) to which to invite the user.
required: true
x-example: "!d41d8cd:matrix.org"
- in: body
name: body
required: true
schema:
type: object
example: |-
{
"id_server": "matrix.org",
"medium": "email",
"address": "cheeky@monkey.com"
}
properties:
id_server:
type: string
description: The hostname+port of the identity server which should be used for third party identifier lookups.
medium:
type: string
# TODO: Link to identity service spec when it eixsts
description: The kind of address being passed in the address field, for example ``email``.
address:
type: string
description: The invitee's third party identifier.
required: ["id_server", "medium", "address"]
responses:
200:
description: The user has been invited to join the room.
examples:
application/json: |-
{}
schema:
type: object
403:
description: |-
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
- The invitee has been banned from the room.
- The invitee is already a member of the room.
- The inviter is not currently in the room.
- The inviter's power level is insufficient to invite users to the room.
examples:
application/json: |-
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
tags:
- Room membership

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Typing API" title: "Matrix Client-Server Typing API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -74,4 +74,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- Room participation

@ -1 +0,0 @@
v1-event-schema/core-event-schema

@ -1,9 +0,0 @@
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": ["event_match", "profile_tag", "contains_display_name", "room_member_count"]
}
}
}

@ -1,20 +0,0 @@
{
"type": "object",
"properties": {
"default": {
"type": "boolean"
},
"enabled": {
"type": "boolean"
},
"rule_id": {
"type": "string"
},
"actions": {
"items": {
"type": ["object", "string"]
},
"type": "array"
}
}
}

@ -1,60 +0,0 @@
{
"type": "object",
"properties": {
"content": {
"items": {
"type": "object",
"allOf": [
{
"$ref": "push_rule.json"
}
]
},
"type": "array"
},
"override": {
"items": {
"type": "object",
"allOf": [
{
"$ref": "push_rule.json"
}
]
},
"type": "array"
},
"sender": {
"items": {
"type": "object",
"allOf": [
{
"$ref": "push_rule.json"
}
]
},
"type": "array"
},
"underride": {
"items": {
"type": "object",
"allOf": [
{
"$ref": "push_rule.json"
}
]
},
"type": "array"
},
"room": {
"items": {
"type": "object",
"allOf": [
{
"$ref": "push_rule.json"
}
]
},
"type": "array"
}
}
}

@ -1,237 +0,0 @@
swagger: '2.0'
info:
title: "Matrix Client-Server v1 Room Membership API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/api/v1
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/join":
post:
summary: Start the requesting user participating in a particular room.
description: |-
This API starts a user participating in a particular room, if that user
is allowed to participate in that room. After this call, the client is
allowed to see all current state events in the room, and all subsequent
events associated with the room until the user leaves the room.
After a user has joined a room, the room will appear as an entry in the
response of the |initialSync| API.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier or room alias to join.
required: true
x-example: "#monkeys:matrix.org"
responses:
200:
description: |-
The room has been joined.
The joined room ID must be returned in the ``room_id`` field.
examples:
application/json: |-
{"room_id": "!d41d8cd:matrix.org"}
schema:
type: object
403:
description: |-
You do not have permission to join the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejection are:
- The room is invite-only and the user was not invited.
- The user has been banned from the room.
examples:
application/json: |-
{"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
x-alias:
canonical-link: "post-matrix-client-api-v1-rooms-roomid-join"
aliases:
- /join/{roomId}
# With an extra " " to disambiguate from the 3pid invite endpoint
# The extra space makes it sort first for what I'm sure is a good reason.
"/rooms/{roomId}/invite ":
post:
summary: Invite a user to participate in a particular room.
description: |-
*Note that there are two forms of this API, which are documented separately.
This version of the API requires that the inviter knows the Matrix
identifier of the invitee.*
This API invites a user to participate in a particular room.
They do not start participating in the room until they actually join the
room.
Only users currently in a particular room can invite other users to
join that room.
If the user was invited to the room, the home server will append a
``m.room.member`` event to the room.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier (not alias) to which to invite the user.
required: true
x-example: "!d41d8cd:matrix.org"
- in: body
name: body
required: true
schema:
type: object
example: |-
{
"user_id": "@cheeky_monkey:matrix.org"
}
properties:
user_id:
type: string
description: The fully qualified user ID of the invitee.
required: ["user_id"]
responses:
200:
description: The user has been invited to join the room.
examples:
application/json: |-
{}
schema:
type: object
403:
description: |-
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
- The invitee has been banned from the room.
- The invitee is already a member of the room.
- The inviter is not currently in the room.
- The inviter's power level is insufficient to invite users to the room.
examples:
application/json: |-
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"
"/rooms/{roomId}/invite":
post:
summary: Invite a user to participate in a particular room.
description: |-
*Note that there are two forms of this API, which are documented separately.
This version of the API does not require that the inviter know the Matrix
identifier of the invitee, and instead relies on third party identifiers.
The homeserver uses an identity server to perform the mapping from
third party identifier to a Matrix identifier.*
This API invites a user to participate in a particular room.
They do not start participating in the room until they actually join the
room.
Only users currently in a particular room can invite other users to
join that room.
If the identity server did know the Matrix user identifier for the
third party identifier, the home server will append a ``m.room.member``
event to the room.
If the identity server does not know a Matrix user identifier for the
passed third party identifier, the homeserver will issue an invitation
which can be accepted upon providing proof of ownership of the third
party identifier. This is achieved by the identity server generating a
token, which it gives to the inviting homeserver. The homeserver will
add an ``m.room.third_party_invite`` event into the graph for the room,
containing that token.
When the invitee binds the invited third party identifier to a Matrix
user ID, the identity server will give the user a list of pending
invitations, each containing:
- The room ID to which they were invited
- The token given to the homeserver
- A signature of the token, signed with the identity server's private key
- The matrix user ID who invited them to the room
If a token is requested from the identity server, the home server will
append a ``m.room.third_party_invite`` event to the room.
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomId
description: The room identifier (not alias) to which to invite the user.
required: true
x-example: "!d41d8cd:matrix.org"
- in: body
name: body
required: true
schema:
type: object
example: |-
{
"id_server": "matrix.org",
"medium": "email",
"address": "cheeky@monkey.com",
"display_name": "A very cheeky monkey"
}
properties:
id_server:
type: string
description: The hostname+port of the identity server which should be used for third party identifier lookups.
medium:
type: string
# TODO: Link to identity service spec when it eixsts
description: The kind of address being passed in the address field, for example ``email``.
address:
type: string
description: The invitee's third party identifier.
display_name:
type: string
description: A user-friendly string describing who has been invited. It should not contain the address of the invitee, to avoid leaking mappings between third party identities and matrix user IDs.
required: ["id_server", "medium", "address", "display_name"]
responses:
200:
description: The user has been invited to join the room.
examples:
application/json: |-
{}
schema:
type: object
403:
description: |-
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
- The invitee has been banned from the room.
- The invitee is already a member of the room.
- The inviter is not currently in the room.
- The inviter's power level is insufficient to invite users to the room.
examples:
application/json: |-
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"

@ -1 +0,0 @@
../../../event-schemas/schema/v1

@ -1 +0,0 @@
../../../event-schemas/schema/v1/core-event-schema

@ -1,10 +0,0 @@
type: object
description: A Matrix-level Error
properties:
errcode:
type: string
description: An error code.
error:
type: string
description: A human-readable error message.
required: ["errcode"]

@ -1,12 +0,0 @@
{
"type": "object",
"properties": {
"events": {
"type": "array",
"description": "List of events",
"items": {
"type": "object"
}
}
}
}

@ -1,42 +0,0 @@
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description":
"The maximum number of events to return."
},
"types": {
"type": "array",
"description":
"A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"not_types": {
"type": "array",
"description":
"A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"senders": {
"type": "array",
"description":
"A list of senders IDs to include. If this list is absent then all senders are included. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"not_senders": {
"type": "array",
"description":
"A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
}
}
}

@ -1,12 +0,0 @@
{
"type": "object",
"properties": {
"events": {
"type": "array",
"description": "List of event ids",
"items": {
"type": "string"
}
}
}
}

@ -1,22 +0,0 @@
{
"type": "object",
"allOf": [{"$ref": "definitions/event_filter.json"}],
"properties": {
"rooms": {
"type": "array",
"description":
"A list of room IDs to include. If this list is absent then all rooms are included. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"not_rooms": {
"type": "array",
"description":
"A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
}
}
}

@ -1,44 +0,0 @@
{
"type": "object",
"properties": {
"room": {
"type": "object",
"properties": {
"state": {
"description":
"The state events to include for rooms.",
"allOf": [{"$ref": "definitions/room_event_filter.json"}]
},
"timeline": {
"description":
"The message and state update events to include for rooms.",
"allOf": [{"$ref": "definitions/room_event_filter.json"}]
},
"ephemeral": {
"description":
"The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms.",
"allOf": [{"$ref": "definitions/room_event_filter.json"}]
}
}
},
"presence": {
"description":
"The presence updates to include.",
"allOf": [{"$ref": "definitions/event_filter.json"}]
},
"event_format": {
"description":
"The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as receieved over federation. The default is 'client'.",
"type": "string",
"enum": ["client", "federation"]
},
"event_fields": {
"type": "array",
"description":
"List of event fields to include. If this list is absent then all fields are included. The entries may include '.' charaters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\\'. A server may include more fields than were requested.",
"items": {
"type": "string"
}
}
}
}

@ -1,14 +0,0 @@
{
"type": "object",
"allOf": [{"$ref":"definitions/room_event_batch.json"}],
"properties": {
"limited": {
"type": "boolean",
"description": "Whether there are more events on the server"
},
"prev_batch": {
"type": "string",
"description": "If the batch was limited then this is a token that can be supplied to the server to retrieve more events"
}
}
}

@ -1,12 +1,12 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server v1 Voice over IP API" title: "Matrix Client-Server Voice over IP API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:
- https - https
- http - http
basePath: /_matrix/client/api/v1 basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes: consumes:
- application/json - application/json
produces: produces:
@ -18,7 +18,7 @@ securityDefinitions:
name: access_token name: access_token
in: query in: query
paths: paths:
"/turnServer": "/voip/turnServer":
get: get:
summary: Obtain TURN server credentials. summary: Obtain TURN server credentials.
description: |- description: |-
@ -65,4 +65,5 @@ paths:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/error.yaml"
tags:
- VOIP

@ -1,17 +1,17 @@
Registration and Login Registration and Login
---------------------- ----------------------
Clients must register with a home server in order to use Matrix. After Clients must register with a homeserver in order to use Matrix. After
registering, the client will be given an access token which must be used in ALL 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'. requests to that homeserver as a query parameter 'access_token'.
If the client has already registered, they need to be able to login to their 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 account. The homeserver may provide many different ways of logging in, such as
user/password auth, login via a social network (OAuth2), login by confirming a 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 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 homeservers should authorise their users who want to login to their existing
accounts, but instead defines the standard interface which implementations accounts, but instead defines the standard interface which implementations
should follow so that ANY client can login to ANY home server. Clients login should follow so that ANY client can login to ANY homeserver. Clients login
using the |login|_ API. Clients register using the |register|_ API. using the |login|_ API. Clients register using the |register|_ API.
Registration follows the same general procedure as login, but the path requests Registration follows the same general procedure as login, but the path requests
are sent to and the details contained in them are different. are sent to and the details contained in them are different.
@ -26,7 +26,7 @@ In order to determine up-front what the server's requirements are, the client
can request from the server a complete description of all of its acceptable can request from the server a complete description of all of its acceptable
flows of the registration or login process. It can then inspect the list of flows of the registration or login process. It can then inspect the list of
returned flows looking for one for which it believes it can complete all of the returned flows looking for one for which it believes it can complete all of the
required stages, and perform it. As each home server may have different ways of required stages, and perform it. As each homeserver may have different ways of
logging in, the client needs to know how they should login. All distinct login 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 stages MUST have a corresponding ``type``. A ``type`` is a namespaced string
which details the mechanism for logging in. which details the mechanism for logging in.
@ -64,12 +64,12 @@ ID and a new access token MUST be returned::
"access_token": "abcdef0123456789" "access_token": "abcdef0123456789"
} }
The ``user_id`` key is particularly useful if the home server wishes to support The ``user_id`` key is particularly useful if the homeserver wishes to support
localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as 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. the client may not be able to determine its ``user_id`` in this case.
If the flow has multiple stages to it, the home server may wish to create a If the flow has multiple stages to it, the homeserver may wish to create a
session to store context between requests. If a home server responds with a session to store context between requests. If a homeserver responds with a
``session`` key to a request, clients MUST submit it in subsequent requests ``session`` key to a request, clients MUST submit it in subsequent requests
until the flow is completed:: until the flow is completed::
@ -99,7 +99,7 @@ To respond to this type, reply with::
"password": "<password>" "password": "<password>"
} }
The home server MUST respond with either new credentials, the next stage of the The homeserver MUST respond with either new credentials, the next stage of the
login process, or a standard error response. login process, or a standard error response.
Captcha-based Captcha-based
@ -123,7 +123,7 @@ To respond to this type, reply with::
Recaptcha.get_challenge(); Recaptcha.get_challenge();
Recaptcha.get_response(); Recaptcha.get_response();
The home server MUST respond with either new credentials, the next stage of the The homeserver MUST respond with either new credentials, the next stage of the
login process, or a standard error response. login process, or a standard error response.
OAuth2-based OAuth2-based
@ -146,24 +146,24 @@ The server MUST respond with::
"uri": <Authorization Request URI OR service selection URI> "uri": <Authorization Request URI OR service selection URI>
} }
The home server acts as a 'confidential' client for the purposes of OAuth2. If The homeserver 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 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, 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 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 service which the homeserver accepts when logging in, this indirection can be
skipped and the "uri" key can be the ``Authorization Request URI``. skipped and the "uri" key can be the ``Authorization Request URI``.
The client then visits the ``Authorization Request URI``, which then shows the The client then visits the ``Authorization Request URI``, which then shows the
OAuth2 Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with 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 auth code. Homeservers can choose any path for the ``redirect URI``. The
client should visit the ``redirect URI``, which will then finish the OAuth2 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. login process, granting the homeserver an access token for the chosen service.
When the home server gets this access token, it verifies that the cilent has When the homeserver gets this access token, it verifies that the cilent has
authorised with the 3rd party, and can now complete the login. The OAuth2 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 ``redirect URI`` (with auth code) MUST respond with either new credentials, the
next stage of the login process, or a standard error response. 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 For example, if a homeserver accepts OAuth2 from Google, it would return the
Authorization Request URI for Google:: Authorization Request URI for Google::
{ {
@ -171,7 +171,7 @@ Authorization Request URI for Google::
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos" client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos"
} }
The client then visits this URI and authorizes the home server. The client then The client then visits this URI and authorizes the homeserver. The client then
visits the REDIRECT_URI with the auth code= query parameter which returns:: visits the REDIRECT_URI with the auth code= query parameter which returns::
{ {
@ -195,7 +195,7 @@ To respond to this type, reply with::
"email": "<email address>" "email": "<email address>"
} }
After validating the email address, the home server MUST send an email After validating the email address, the homeserver MUST send an email
containing an authentication code and return:: containing an authentication code and return::
{ {
@ -212,7 +212,7 @@ code::
"code": "<code in email sent>" "code": "<code in email sent>"
} }
The home server MUST respond to this with either new credentials, the next The homeserver MUST respond to this with either new credentials, the next
stage of the login process, or a standard error response. stage of the login process, or a standard error response.
Email-based (url) Email-based (url)
@ -231,7 +231,7 @@ To respond to this type, reply with::
"email": "<email address>" "email": "<email address>"
} }
After validating the email address, the home server MUST send an email After validating the email address, the homeserver MUST send an email
containing an authentication URL and return:: containing an authentication URL and return::
{ {
@ -247,7 +247,7 @@ client should perform another request::
"session": "<session id>" "session": "<session id>"
} }
The home server MUST respond to this with either new credentials, the next The homeserver MUST respond to this with either new credentials, the next
stage of the login process, or a standard error response. stage of the login process, or a standard error response.
A common client implementation will be to periodically poll until the link is A common client implementation will be to periodically poll until the link is
@ -264,7 +264,7 @@ Email-based (identity server)
Prior to submitting this, the client should authenticate with an identity Prior to submitting this, the client should authenticate with an identity
server. After authenticating, the session information should be submitted to server. After authenticating, the session information should be submitted to
the home server. the homeserver.
To respond to this type, reply with:: To respond to this type, reply with::
@ -293,7 +293,7 @@ of a previous login stage::
"next": "<next login type>" "next": "<next login type>"
} }
If a home server implements N-factor authentication, it MUST respond with all If a homeserver implements N-factor authentication, it MUST respond with all
``stages`` when initially queried for their login requirements:: ``stages`` when initially queried for their login requirements::
{ {

@ -0,0 +1,37 @@
r0
===
This is the first release of the client-server specification. It is largely a dump of what has currently been implemented, and there are several inconsistencies.
An upcoming minor release will deprecate many of these inconsistencies, and they will be removed in the next major release.
Since the draft stage, the following major changes have been made:
- /api/v1 and /v2_alpha path segments have been replaced with the major version of the release (i.e. 'r0').
- Some POST versions of APIs with both POST and PUT have been removed.
- The specification has been split into one specification per API. This is the client-server API. The server-server API can be found documented separately.
- All APIs are now documented using Swagger
- The following modules have been added:
- Content repository
- Instant messaging
- Push notification
- History visibility
- Search
- Invites based on third party identifiers
- Room tagging
- Guest access
- Client config
- The following APIs were added:
- ``/sync``
- ``/publicRooms``
- ``/rooms/{roomId}/forget``
- ``/admin/whois``
- ``/rooms/{roomId}/redact``
- ``/user/{userId}/filter``
- The following APIs have been significantly modified:
- Invitations now contain partial room state
- Invitations can now be rejected
- ``/directory``
- The following events have been added:
- ``m.room.avatar``
- Example signed json is included for reference
- Commentary on display name calculation was added

@ -1,11 +1,11 @@
Versioning is, like, hard for backfilling backwards because of the number of Home Servers involved. Versioning is, like, hard for backfilling backwards because of the number of homeservers involved.
The way we solve this is by doing versioning as an acyclic directed graph of PDUs. For backfilling purposes, this is done on a per context basis. The way we solve this is by doing versioning as an acyclic directed graph of PDUs. For backfilling purposes, this is done on a per context basis.
When we send a PDU we include all PDUs that have been received for that context that hasn't been subsequently listed in a later PDU. The trivial case is a simple list of PDUs, e.g. A <- B <- C. However, if two servers send out a PDU at the same to, both B and C would point at A - a later PDU would then list both B and C. When we send a PDU we include all PDUs that have been received for that context that hasn't been subsequently listed in a later PDU. The trivial case is a simple list of PDUs, e.g. A <- B <- C. However, if two servers send out a PDU at the same to, both B and C would point at A - a later PDU would then list both B and C.
Problems with opaque version strings: Problems with opaque version strings:
- How do you do clustering without mandating that a cluster can only have one transaction in flight to a given remote home server at a time. - How do you do clustering without mandating that a cluster can only have one transaction in flight to a given remote homeserver at a time.
If you have multiple transactions sent at once, then you might drop one transaction, receive another with a version that is later than the dropped transaction and which point ARGH WE LOST A TRANSACTION. If you have multiple transactions sent at once, then you might drop one transaction, receive another with a version that is later than the dropped transaction and which point ARGH WE LOST A TRANSACTION.
- How do you do backfilling? A version string defines a point in a stream w.r.t. a single home server, not a point in the context. - How do you do backfilling? A version string defines a point in a stream w.r.t. a single homeserver, not a point in the context.
We only need to store the ends of the directed graph, we DO NOT need to do the whole one table of nodes and one of edges. We only need to store the ends of the directed graph, we DO NOT need to do the whole one table of nodes and one of edges.

@ -13,9 +13,9 @@ Application Services HTTP API
.. sectnum:: .. sectnum::
Application Service -> Home Server Application Service -> Homeserver
---------------------------------- ----------------------------------
This contains home server APIs which are used by the application service. This contains homeserver APIs which are used by the application service.
Registration API ``[Draft]`` Registration API ``[Draft]``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -34,7 +34,7 @@ Output:
Side effects: Side effects:
- The HS will start delivering events to the URL base specified if this 200s. - The HS will start delivering events to the URL base specified if this 200s.
API called when: API called when:
- The application service wants to register with a brand new home server. - The application service wants to register with a brand new homeserver.
Notes: Notes:
- An application service can state whether they should be the only ones who - An application service can state whether they should be the only ones who
can manage a specified namespace. This is referred to as an "exclusive" can manage a specified namespace. This is referred to as an "exclusive"
@ -100,7 +100,7 @@ Notes:
Unregister API ``[Draft]`` Unregister API ``[Draft]``
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
This API unregisters a previously registered AS from the home server. This API unregisters a previously registered AS from the homeserver.
Inputs: Inputs:
- AS token - AS token
@ -122,9 +122,9 @@ API called when:
} }
Home Server -> Application Service Homeserver -> Application Service
---------------------------------- ----------------------------------
This contains application service APIs which are used by the home server. This contains application service APIs which are used by the homeserver.
User Query ``[Draft]`` User Query ``[Draft]``
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
@ -152,9 +152,9 @@ Notes:
- This is deemed more flexible than alternative methods (e.g. returning a JSON blob with the - This is deemed more flexible than alternative methods (e.g. returning a JSON blob with the
user's display name and get the HS to provision the user). user's display name and get the HS to provision the user).
Retry notes: Retry notes:
- The home server cannot respond to the client's request until the response to - The homeserver cannot respond to the client's request until the response to
this API is obtained from the AS. this API is obtained from the AS.
- Recommended that home servers try a few times then time out, returning a - Recommended that homeservers try a few times then time out, returning a
408 Request Timeout to the client. 408 Request Timeout to the client.
:: ::
@ -199,9 +199,9 @@ Notes:
style JSON blob and get the HS to provision the room). It also means that the AS knows style JSON blob and get the HS to provision the room). It also means that the AS knows
the room ID -> alias mapping. the room ID -> alias mapping.
Retry notes: Retry notes:
- The home server cannot respond to the client's request until the response to - The homeserver cannot respond to the client's request until the response to
this API is obtained from the AS. this API is obtained from the AS.
- Recommended that home servers try a few times then time out, returning a - Recommended that homeservers try a few times then time out, returning a
408 Request Timeout to the client. 408 Request Timeout to the client.
:: ::
@ -236,13 +236,13 @@ Data flows:
:: ::
Typical Typical
HS ---> AS : Home server sends events with transaction ID T. HS ---> AS : Homeserver sends events with transaction ID T.
<--- : AS sends back 200 OK. <--- : AS sends back 200 OK.
AS ACK Lost AS ACK Lost
HS ---> AS : Home server sends events with transaction ID T. HS ---> AS : Homeserver sends events with transaction ID T.
<-/- : AS 200 OK is lost. <-/- : AS 200 OK is lost.
HS ---> AS : Home server retries with the same transaction ID of T. HS ---> AS : Homeserver retries with the same transaction ID of T.
<--- : AS sends back 200 OK. If the AS had processed these events <--- : AS sends back 200 OK. If the AS had processed these events
already, it can NO-OP this request (and it knows if it is the same already, it can NO-OP this request (and it knows if it is the same
events based on the transacton ID). events based on the transacton ID).
@ -253,15 +253,15 @@ Retry notes:
- Since ASes by definition cannot alter the traffic being passed to it (unlike - Since ASes by definition cannot alter the traffic being passed to it (unlike
say, a Policy Server), these requests can be done in parallel to general HS say, a Policy Server), these requests can be done in parallel to general HS
processing; the HS doesn't need to block whilst doing this. processing; the HS doesn't need to block whilst doing this.
- Home servers should use exponential backoff as their retry algorithm. - Homeservers should use exponential backoff as their retry algorithm.
- Home servers MUST NOT alter (e.g. add more) events they were going to - Homeservers MUST NOT alter (e.g. add more) events they were going to
send within that transaction ID on retries, as the AS may have already send within that transaction ID on retries, as the AS may have already
processed the events. processed the events.
Ordering notes: Ordering notes:
- The events sent to the AS should be linearised, as they are from the event - The events sent to the AS should be linearised, as they are from the event
stream. stream.
- The home server will need to maintain a queue of transactions to send to - The homeserver will need to maintain a queue of transactions to send to
the AS. the AS.
:: ::
@ -336,7 +336,7 @@ Notes:
Server admin style permissions Server admin style permissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The home server needs to give the application service *full control* over its The homeserver needs to give the application service *full control* over its
namespace, both for users and for room aliases. This means that the AS should namespace, both for users and for room aliases. This means that the AS should
be able to create/edit/delete any room alias in its namespace, as well as be able to create/edit/delete any room alias in its namespace, as well as
create/delete any user in its namespace. No additional API changes need to be create/delete any user in its namespace. No additional API changes need to be
@ -451,15 +451,15 @@ Examples
IRC IRC
~~~ ~~~
Pre-conditions: Pre-conditions:
- Server admin stores the AS token "T_a" on the home server. - Server admin stores the AS token "T_a" on the homeserver.
- Home server has a token "T_h". - Homeserver has a token "T_h".
- Home server has the domain "hsdomain.com" - Homeserver has the domain "hsdomain.com"
1. Application service registration 1. Application service registration
:: ::
AS -> HS: Registers itself with the home server AS -> HS: Registers itself with the homeserver
POST /register POST /register
{ {
url: "https://someapp.com/matrix", url: "https://someapp.com/matrix",

@ -237,7 +237,7 @@ Domain specific string
``room_id`` ``room_id``
A domain specific string with prefix ``!`` that is static across all events A domain specific string with prefix ``!`` that is static across all events
in a graph and uniquely identifies it. The ``domain`` should be that of the in a graph and uniquely identifies it. The ``domain`` should be that of the
home server that created the room (i.e., the server that generated the homeserver that created the room (i.e., the server that generated the
first ``m.room.create`` event). first ``m.room.create`` event).
``sender`` ``sender``
@ -246,7 +246,7 @@ Domain specific string
User Id User Id
A domain specific string with prefix ``@`` representing a user account. The A domain specific string with prefix ``@`` representing a user account. The
``domain`` is the home server of the user and is the server used to contact ``domain`` is the homeserver of the user and is the server used to contact
the user. the user.
Joining a room Joining a room
@ -280,7 +280,7 @@ can then process the join event itself.
Inviting a user Inviting a user
--------------- ---------------
To invite a remote user to a room we need their home server to sign the invite To invite a remote user to a room we need their homeserver to sign the invite
event. This is done by sending the event to the remote server, which then signs event. This is done by sending the event to the remote server, which then signs
the event, before distributing the invite to other servers. the event, before distributing the invite to other servers.

@ -61,7 +61,7 @@ This version will change the path prefix for HTTP:
- Version 2: ``/_matrix/client/v2`` - Version 2: ``/_matrix/client/v2``
Note the lack of the ``api`` segment. This is for consistency between other Note the lack of the ``api`` segment. This is for consistency between other
home server path prefixes. homeserver path prefixes.
Terminology: Terminology:
- ``Chunk token`` : An opaque string which can be used to return another chunk - ``Chunk token`` : An opaque string which can be used to return another chunk
@ -169,16 +169,16 @@ Outputs:
``content`` key. Deleted message events are ``m.room.redaction`` events. ``content`` key. Deleted message events are ``m.room.redaction`` events.
- New position in the stream. (chunk token) - New position in the stream. (chunk token)
State Events Ordering Notes: State Events Ordering Notes:
- Home servers may receive state events over federation that are superceded by - Homeservers may receive state events over federation that are superceded by
state events previously sent to the client. The home server *cannot* send state events previously sent to the client. The homeserver *cannot* send
these events to the client else they would end up erroneously clobbering the these events to the client else they would end up erroneously clobbering the
superceding state event. superceding state event.
- As a result, the home server reserves the right to omit sending state events - As a result, the homeserver reserves the right to omit sending state events
which are known to be superceded already. which are known to be superceded already.
- This may result in missed *state* events. However, the state of the room will - This may result in missed *state* events. However, the state of the room will
always be eventually consistent. always be eventually consistent.
Message Events Ordering Notes: Message Events Ordering Notes:
- Home servers may receive message events over federation that happened a long - Homeservers may receive message events over federation that happened a long
time ago. The client may or may not be interested in these message events. time ago. The client may or may not be interested in these message events.
- For clients which do not store scrollback for a room (they discard events - For clients which do not store scrollback for a room (they discard events
after processing them), this is not a problem as they only care about the after processing them), this is not a problem as they only care about the
@ -191,11 +191,11 @@ Message Events Ordering Notes:
- The event, when it comes down the stream, will indicate which event it comes - The event, when it comes down the stream, will indicate which event it comes
after. after.
Rejected events: Rejected events:
- A home server may find out via federation that it should not have accepted - A homeserver may find out via federation that it should not have accepted
an event (e.g. to send a message/state event in a room). For example, it may an event (e.g. to send a message/state event in a room). For example, it may
send an event to another home server and receive an auth event stating send an event to another homeserver and receive an auth event stating
that the event should not have been sent. that the event should not have been sent.
- If this happens, the home server will send a ``m.room.redaction`` for the - If this happens, the homeserver will send a ``m.room.redaction`` for the
event in question. This will be a local server event (not shared with other event in question. This will be a local server event (not shared with other
servers). servers).
- If the event was a state event, it will synthesise a new state event to - If the event was a state event, it will synthesise a new state event to
@ -206,7 +206,7 @@ Unknown rooms:
- You could receive events for rooms you are unaware of (e.g. you didn't do an - You could receive events for rooms you are unaware of (e.g. you didn't do an
initial sync, or your HS lost its database and is told from another HS that initial sync, or your HS lost its database and is told from another HS that
they are in this room). How do you handle this? they are in this room). How do you handle this?
- The simplest option would be to redo the initial sync with a filter on the - The simplest option would be to redo the initial sync with a filter on the
room ID you're unaware of. This would retrieve the room state so you can room ID you're unaware of. This would retrieve the room state so you can
display the room. display the room.
What data flows does it address: What data flows does it address:
@ -291,7 +291,7 @@ Scrollback API ``[Draft]``
but as a purely informational display thing it would be nice. but as a purely informational display thing it would be nice.
Additional Inputs: Additional Inputs:
- flag to say if the home server should do a backfill over federation - flag to say if the homeserver should do a backfill over federation
Additional Outputs: Additional Outputs:
- whether there are more events on the local HS / over federation. - whether there are more events on the local HS / over federation.
What data flows does it address: What data flows does it address:
@ -313,7 +313,7 @@ Additional Outputs:
Room Alias API ``[Draft]`` Room Alias API ``[Draft]``
-------------------------- --------------------------
This provides mechanisms for creating and removing room aliases for a room on a This provides mechanisms for creating and removing room aliases for a room on a
home server. Typically, any user in a room can make an alias for that room. The homeserver. Typically, any user in a room can make an alias for that room. The
alias creator (or anyone in the room?) can delete that alias. Server admins can alias creator (or anyone in the room?) can delete that alias. Server admins can
also delete any alias on their server. also delete any alias on their server.
@ -323,7 +323,7 @@ Inputs:
- Room Alias - Room Alias
Output: Output:
- Room ID - Room ID
- List of home servers to join via. - List of homeservers to join via.
Mapping a room to an alias: Mapping a room to an alias:
@ -334,7 +334,7 @@ Inputs:
Output: Output:
- Room alias - Room alias
Notes: Notes:
- The home server may add restrictions e.g. the user must be in the room. - The homeserver may add restrictions e.g. the user must be in the room.
Deleting a mapping: Deleting a mapping:
@ -347,11 +347,11 @@ Output:
Published room list API ``[Draft]`` Published room list API ``[Draft]``
----------------------------------- -----------------------------------
This provides mechanisms for searching for published rooms on a home server. This provides mechanisms for searching for published rooms on a homeserver.
Inputs: Inputs:
- Search text (e.g. room alias/name/topic to search on) - Search text (e.g. room alias/name/topic to search on)
- Home server to search on (this may just be the URL hit for HTTP) - Homeserver to search on (this may just be the URL hit for HTTP)
- Any existing pagination token, can be missing if this is the first hit. - Any existing pagination token, can be missing if this is the first hit.
- Limit for pagination - Limit for pagination
Output: Output:
@ -378,7 +378,7 @@ Notes:
User Profile API ``[Draft]`` User Profile API ``[Draft]``
---------------------------- ----------------------------
Every user on a home server has a profile. This profile is effectively a Every user on a homeserver has a profile. This profile is effectively a
key-value store scoped to a user ID. It can include an ``avatar_url``, key-value store scoped to a user ID. It can include an ``avatar_url``,
``displayname`` and other metadata. Updates to a profile should propagate to ``displayname`` and other metadata. Updates to a profile should propagate to
other interested users. other interested users.
@ -435,7 +435,7 @@ This had a number of problems associated with it:
flicker. flicker.
- Name/avatar changes created more ``m.room.member`` events which meant - Name/avatar changes created more ``m.room.member`` events which meant
they needed to be included in the auth chains for federation. This they needed to be included in the auth chains for federation. This
created long auth chains which is suboptimal since home servers need created long auth chains which is suboptimal since homeservers need
to store the auth chains forever. to store the auth chains forever.
These problems can be resolved by creating an ``m.room.member.profile`` These problems can be resolved by creating an ``m.room.member.profile``
@ -448,7 +448,7 @@ However, this introduces its own set of problems, namely flicker. The
client would receive the ``m.room.member`` event first, followed by client would receive the ``m.room.member`` event first, followed by
the ``m.room.member.profile`` event, which could cause a flicker. In the ``m.room.member.profile`` event, which could cause a flicker. In
addition, federation may not send both events in a single transaction, addition, federation may not send both events in a single transaction,
resulting in missing information on the receiving home server. resulting in missing information on the receiving homeserver.
For federation, these problems can be resolved by sending the For federation, these problems can be resolved by sending the
``m.room.member`` event as they are in v1 (with ``displayname`` and ``m.room.member`` event as they are in v1 (with ``displayname`` and
@ -457,7 +457,7 @@ they cannot be in the ``unsigned`` part of the event. The receiving home
server will then extract these keys and create a server-generated server will then extract these keys and create a server-generated
``m.room.member.profile`` event. To avoid confusion with duplicate ``m.room.member.profile`` event. To avoid confusion with duplicate
information, the ``avatar_url`` and ``displayname`` keys should be information, the ``avatar_url`` and ``displayname`` keys should be
removed from the ``m.room.member`` event by the receiving home server. removed from the ``m.room.member`` event by the receiving homeserver.
When a client requests these events (either from the event stream When a client requests these events (either from the event stream
or from an initial sync), the server will send the generated or from an initial sync), the server will send the generated
``m.room.member.profile`` event under the ``unsigned.profile`` key of the ``m.room.member.profile`` event under the ``unsigned.profile`` key of the
@ -840,17 +840,17 @@ information per device to all other users just redirects the union problem to
the client, which will commonly be presenting this information as an icon the client, which will commonly be presenting this information as an icon
alongside the user. alongside the user.
When a client hits the event stream, the home server can treat the user as When a client hits the event stream, the homeserver can treat the user as
"online". This behaviour should be able to be overridden to avoid flicker "online". This behaviour should be able to be overridden to avoid flicker
during connection losses when the client is appear offline (e.g. device is during connection losses when the client is appear offline (e.g. device is
appear offline > goes into a tunnel > server times out > device regains appear offline > goes into a tunnel > server times out > device regains
connection and hits the event stream forcing the device online before the connection and hits the event stream forcing the device online before the
"appear offline" state can be set). When the client has not hit the event "appear offline" state can be set). When the client has not hit the event
stream for a certain period of time, the home server can treat the user as stream for a certain period of time, the homeserver can treat the user as
"offline". The user can also set a global *per-user* appear offline flag. "offline". The user can also set a global *per-user* appear offline flag.
The user should also be able to set their presence state via a direct API, The user should also be able to set their presence state via a direct API,
without having to hit the event stream. The home server will set a timer when without having to hit the event stream. The homeserver will set a timer when
the connection ends, after which it will set that device to offline. the connection ends, after which it will set that device to offline.
As the idle flag and online state is determined per device, there needs to be a As the idle flag and online state is determined per device, there needs to be a
@ -970,12 +970,12 @@ the hashes the same is the best as that means clients do not need to request
the capabilities for the given hash. the capabilities for the given hash.
On first signup, the client will attempt to send the hash and be most likely On first signup, the client will attempt to send the hash and be most likely
refused by the home server as it does not know the full capability set for that refused by the homeserver as it does not know the full capability set for that
hash. The client will then have to upload the full capability set to the home hash. The client will then have to upload the full capability set to the home
server. The client will then be able to send the hash as normal. server. The client will then be able to send the hash as normal.
When a client receives a hash, the client will either recognise the hash or When a client receives a hash, the client will either recognise the hash or
will have to request the capability set from their home server: will have to request the capability set from their homeserver:
Inputs: Inputs:
- Hash - Hash
@ -1070,7 +1070,7 @@ Main use cases for ``updates``:
- Call signalling (child events are ICE candidates, answer to the offer, and - Call signalling (child events are ICE candidates, answer to the offer, and
termination) termination)
- *Local* Delivery/Read receipts : "Local" means they are not shared with other - *Local* Delivery/Read receipts : "Local" means they are not shared with other
users on the same home server or via federation but *are* shared between users on the same homeserver or via federation but *are* shared between
clients for the same user; useful for push notifications, read count markers, clients for the same user; useful for push notifications, read count markers,
etc. This is done to avoid the ``n^2`` problem for sending receipts, where etc. This is done to avoid the ``n^2`` problem for sending receipts, where
the vast majority of traffic tends towards sending more receipts. the vast majority of traffic tends towards sending more receipts.
@ -1168,11 +1168,11 @@ Events (breaking changes; event version 2) ``[Draft]``
when dealing with custom event types. E.g. ``_custom.event`` would allow when dealing with custom event types. E.g. ``_custom.event`` would allow
anything in the state key, ``_@custom.event`` would only allow user IDs in anything in the state key, ``_@custom.event`` would only allow user IDs in
the state key, etc. the state key, etc.
- s/user_id/sender/g given that home servers can send events, not just users. - s/user_id/sender/g given that homeservers can send events, not just users.
Server-generated events ``[Draft]`` Server-generated events ``[Draft]``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Home servers may want to send events to their local clients or to other home Homeservers may want to send events to their local clients or to other home
servers e.g. for server status notifications. servers e.g. for server status notifications.
These events look like regular events but have a server domain name as the These events look like regular events but have a server domain name as the

@ -13,9 +13,9 @@ phishing/spoofing of IDs, commonly known as a homograph attack.
Web browers encountered this problem when International Domain Names were Web browers encountered this problem when International Domain Names were
introduced. A variety of checks were put in place in order to protect users. If introduced. A variety of checks were put in place in order to protect users. If
an address failed the check, the raw punycode would be displayed to an address failed the check, the raw punycode would be displayed to
disambiguate the address. Similar checks are performed by home servers in disambiguate the address. Similar checks are performed by homeservers in
Matrix. However, Matrix does not use punycode representations, and so does not Matrix. However, Matrix does not use punycode representations, and so does not
show raw punycode on a failed check. Instead, home servers must outright reject show raw punycode on a failed check. Instead, homeservers must outright reject
these misleading IDs. these misleading IDs.
Types of human-readable IDs Types of human-readable IDs
@ -48,12 +48,12 @@ Checks
Rejecting Rejecting
--------- ---------
- Home servers MUST reject room aliases which do not pass the check, both on - Homeservers MUST reject room aliases which do not pass the check, both on
GETs and PUTs. GETs and PUTs.
- Home servers MUST reject user ID localparts which do not pass the check, both - Homeservers MUST reject user ID localparts which do not pass the check, both
on creation and on events. on creation and on events.
- Any home server whose domain does not pass this check, MUST use their punycode - Any homeserver whose domain does not pass this check, MUST use their punycode
domain name instead of the IDN, to prevent other home servers rejecting you. domain name instead of the IDN, to prevent other homeservers rejecting you.
- Error code is ``M_FAILED_HUMAN_ID_CHECK``. (generic enough for both failing - Error code is ``M_FAILED_HUMAN_ID_CHECK``. (generic enough for both failing
due to homograph attacks, and failing due to including ``:`` s, etc) due to homograph attacks, and failing due to including ``:`` s, etc)
- Error message MAY go into further information about which characters were - Error message MAY go into further information about which characters were
@ -74,7 +74,7 @@ Other considerations
- High security: Outright rejection of the ID at the point of creation / - High security: Outright rejection of the ID at the point of creation /
receiving event. Point of creation rejection is preferable to avoid the ID receiving event. Point of creation rejection is preferable to avoid the ID
entering the system in the first place. However, malicious HSes can just entering the system in the first place. However, malicious HSes can just
allow the ID. Hence, other home servers must reject them if they see them in allow the ID. Hence, other homeservers must reject them if they see them in
events. Client never sees the problem ID, provided the HS is correctly events. Client never sees the problem ID, provided the HS is correctly
implemented. implemented.
- High security decided; client doesn't need to worry about it, no additional - High security decided; client doesn't need to worry about it, no additional

@ -9,26 +9,35 @@ Caveats can only be used for reducing the scope of a token, never for increasing
Some caveats are specified in this specification, and must be understood by all servers. The use of non-standard caveats is allowed. Some caveats are specified in this specification, and must be understood by all servers. The use of non-standard caveats is allowed.
All caveats must take the form: All caveats must take the form::
`key` `operator` `value` key operator value
where `key` is a non-empty string drawn from the character set [A-Za-z0-9_]
`operator` is a non-empty string which does not contain whitespace where:
`value` is a non-empty string - ``key`` is a non-empty string drawn from the character set [A-Za-z0-9_]
- ``operator`` is a non-empty string which does not contain whitespace
- ``value`` is a non-empty string
And these are joined by single space characters. And these are joined by single space characters.
Specified caveats: Specified caveats:
+-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+ +-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+
| Caveat name | Description | Legal Values | | Caveat name | Description | Legal Values |
+-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+ +=============+==================================================+================================================================================================+
| gen | Generation of the macaroon caveat spec. | 1 | | gen | Generation of the macaroon caveat spec. | 1 |
+-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+
| user_id | ID of the user for which this macaroon is valid. | Pure equality check. Operator must be =. | | user_id | ID of the user for which this macaroon is valid. | Pure equality check. Operator must be =. |
| type | The purpose of this macaroon. | access - used to authorize any action except token refresh | +-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+
| refresh - only used to authorize a token refresh | | type | The purpose of this macaroon. | - ``access``: used to authorize any action except token refresh |
| | | - ``refresh``: only used to authorize a token refresh |
| | | - ``login``: issued as a very short-lived token by third party login flows; proves that |
| | | authentication has happened but doesn't grant any privileges other than being able to be |
| | | exchanged for other tokens. |
+-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+
| time | Time before/after which this macaroon is valid. | A POSIX timestamp in milliseconds (in UTC). | | time | Time before/after which this macaroon is valid. | A POSIX timestamp in milliseconds (in UTC). |
| Operator < means the macaroon is valid before the timestamp, as interpreted by the server. | | | | Operator < means the macaroon is valid before the timestamp, as interpreted by the server. |
| Operator > means the macaroon is valid after the timestamp, as interpreted by the server. | | | | Operator > means the macaroon is valid after the timestamp, as interpreted by the server. |
| Operator == means the macaroon is valid at exactly the timestamp, as interpreted by the server.| | | | Operator == means the macaroon is valid at exactly the timestamp, as interpreted by the server.|
| Note that exact equality of time is largely meaningless. | | | | Note that exact equality of time is largely meaningless. |
+-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+ +-------------+--------------------------------------------------+------------------------------------------------------------------------------------------------+

@ -5,14 +5,14 @@ A simple implementation of presence messaging has the ability to cause a large
amount of Internet traffic relating to presence updates. In order to minimise amount of Internet traffic relating to presence updates. In order to minimise
the impact of such a feature, the following observations can be made: the impact of such a feature, the following observations can be made:
* There is no point in a Home Server polling status for peers in a user's * There is no point in a homeserver polling status for peers in a user's
presence list if the user has no clients connected that care about it. presence list if the user has no clients connected that care about it.
* It is highly likely that most presence subscriptions will be symmetric - a * It is highly likely that most presence subscriptions will be symmetric - a
given user watching another is likely to in turn be watched by that user. given user watching another is likely to in turn be watched by that user.
* It is likely that most subscription pairings will be between users who share * It is likely that most subscription pairings will be between users who share
at least one Room in common, and so their Home Servers are actively at least one Room in common, and so their homeservers are actively
exchanging message PDUs or transactions relating to that Room. exchanging message PDUs or transactions relating to that Room.
* Presence update messages do not need realtime guarantees. It is acceptable to * Presence update messages do not need realtime guarantees. It is acceptable to
@ -25,7 +25,7 @@ promise to send them when required. Rather than actively polling for the
current state all the time, HSes can rely on their relative stability to only current state all the time, HSes can rely on their relative stability to only
push updates when required. push updates when required.
A Home Server should not rely on the longterm validity of this presence A homeserver should not rely on the longterm validity of this presence
information, however, as this would not cover such cases as a user's server information, however, as this would not cover such cases as a user's server
crashing and thus failing to inform their peers that users it used to host are crashing and thus failing to inform their peers that users it used to host are
no longer available online. Therefore, each promise of future updates should no longer available online. Therefore, each promise of future updates should
@ -33,7 +33,7 @@ carry with a timeout value (whether explicit in the message, or implicit as some
defined default in the protocol), after which the receiving HS should consider defined default in the protocol), after which the receiving HS should consider
the information potentially stale and request it again. the information potentially stale and request it again.
However, because of the likelihood that two home servers are exchanging messages However, because of the likelihood that two homeservers are exchanging messages
relating to chat traffic in a room common to both of them, the ongoing receipt relating to chat traffic in a room common to both of them, the ongoing receipt
of these messages can be taken by each server as an implicit notification that of these messages can be taken by each server as an implicit notification that
the sending server is still up and running, and therefore that no status changes the sending server is still up and running, and therefore that no status changes
@ -98,7 +98,7 @@ The data model presented here puts the following requirements on the APIs:
Client-Server Client-Server
------------- -------------
Requests that a client can make to its Home Server Requests that a client can make to its homeserver
* get/set current presence state * get/set current presence state
Basic enumeration + ability to set a custom piece of text Basic enumeration + ability to set a custom piece of text
@ -128,7 +128,7 @@ Requests that a client can make to its Home Server
Server-Server Server-Server
------------- -------------
Requests that Home Servers make to others Requests that homeservers make to others
* request permission to add a user to presence list * request permission to add a user to presence list

@ -9,7 +9,7 @@ Overview
======== ========
Internally within Synapse users are referred to by an opaque ID, which consists Internally within Synapse users are referred to by an opaque ID, which consists
of some opaque localpart combined with the domain name of their home server. of some opaque localpart combined with the domain name of their homeserver.
Obviously this does not yield a very nice user experience; users would like to Obviously this does not yield a very nice user experience; users would like to
see readable names for other users that are in some way meaningful to them. see readable names for other users that are in some way meaningful to them.
Additionally, users like to be able to publish "profile" details to inform other Additionally, users like to be able to publish "profile" details to inform other
@ -59,7 +59,7 @@ servers should be accounted for here.]]
Visibility Permissions Visibility Permissions
====================== ======================
A home server implementation could offer the ability to set permissions on A homeserver implementation could offer the ability to set permissions on
limited visibility of those fields. When another user requests access to the limited visibility of those fields. When another user requests access to the
target user's profile, their own identity should form part of that request. The target user's profile, their own identity should form part of that request. The
HS implementation can then decide which fields to make available to the HS implementation can then decide which fields to make available to the
@ -130,12 +130,12 @@ namespace to allocate names into.
It would also be nice from a user experience perspective if the profile that a It would also be nice from a user experience perspective if the profile that a
given name links to can also declare that name as part of its metadata. given name links to can also declare that name as part of its metadata.
Furthermore as a security and consistency perspective it would be nice if each Furthermore as a security and consistency perspective it would be nice if each
end (the directory server and the user's home server) check the validity of the end (the directory server and the user's homeserver) check the validity of the
mapping in some way. This needs investigation from a security perspective to mapping in some way. This needs investigation from a security perspective to
ensure against spoofing. ensure against spoofing.
One such model may be that the user starts by declaring their intent to use a One such model may be that the user starts by declaring their intent to use a
given user name link to their home server, which then contacts the directory given user name link to their homeserver, which then contacts the directory
service. At some point later (maybe immediately for "public open FCFS servers", service. At some point later (maybe immediately for "public open FCFS servers",
maybe after some kind of human intervention for verification) the DS decides to maybe after some kind of human intervention for verification) the DS decides to
honour this link, and includes it in its served output. It should also tell the honour this link, and includes it in its served output. It should also tell the
@ -170,7 +170,7 @@ balancing choice on behalf of the user who would choose, or not, to make use of
such a feature to publish their information. such a feature to publish their information.
Additionally, unless some form of strong end-to-end user-based encryption is Additionally, unless some form of strong end-to-end user-based encryption is
used, a user of ACLs for information privacy has to trust other home servers not used, a user of ACLs for information privacy has to trust other homeservers not
to lie about the identify of the user requesting access to the Profile. to lie about the identify of the user requesting access to the Profile.
@ -182,7 +182,7 @@ The data model presented here puts the following requirements on the APIs:
Client-Server Client-Server
------------- -------------
Requests that a client can make to its Home Server Requests that a client can make to its homeserver
* get/set my Display Name * get/set my Display Name
This should return/take a simple "text/plain" field This should return/take a simple "text/plain" field
@ -207,7 +207,7 @@ TODO(paul): At some later stage we should consider the API for:
Server-Server Server-Server
------------- -------------
Requests that Home Servers make to others Requests that homeservers make to others
* get a user's Display Name / Avatar * get a user's Display Name / Avatar
@ -221,7 +221,7 @@ Requests that Home Servers make to others
Room Event PDU Types Room Event PDU Types
-------------------- --------------------
Events that are pushed from Home Servers to other Home Servers or clients. Events that are pushed from homeservers to other homeservers or clients.
* user Display Name change * user Display Name change

@ -8,7 +8,7 @@ Discovery
========= =========
To join a room, a user has to discover the room by some mechanism in order to To join a room, a user has to discover the room by some mechanism in order to
obtain the (opaque) Room ID and a candidate list of likely home servers that obtain the (opaque) Room ID and a candidate list of likely homeservers that
contain it. contain it.
Sending an Invitation Sending an Invitation
@ -21,7 +21,7 @@ The inviter's HS sets the membership status of the invitee to "invited" in the
"m.members" state key by sending a state update PDU. The HS then broadcasts this "m.members" state key by sending a state update PDU. The HS then broadcasts this
PDU among the existing members in the usual way. An invitation message is also PDU among the existing members in the usual way. An invitation message is also
sent to the invited user, containing the Room ID and the PDU ID of this sent to the invited user, containing the Room ID and the PDU ID of this
invitation state change and potentially a list of some other home servers to use invitation state change and potentially a list of some other homeservers to use
to accept the invite. The user's client can then choose to display it in some to accept the invite. The user's client can then choose to display it in some
way to alert the user. way to alert the user.
@ -34,7 +34,7 @@ Directory Service
Alternatively, the user may discover the channel via a directory service; either Alternatively, the user may discover the channel via a directory service; either
by performing a name lookup, or some kind of browse or search acitivty. However by performing a name lookup, or some kind of browse or search acitivty. However
this is performed, the end result is that the user's home server requests the this is performed, the end result is that the user's homeserver requests the
Room ID and candidate list from the directory service. Room ID and candidate list from the directory service.
[[TODO(paul): At present, no API has been designed or described for this [[TODO(paul): At present, no API has been designed or described for this
@ -44,14 +44,14 @@ directory service]]
Joining Joining
======= =======
Once the ID and home servers are obtained, the user can then actually join the Once the ID and homeservers are obtained, the user can then actually join the
room. room.
Accepting an Invite Accepting an Invite
------------------- -------------------
If a user has received and accepted an invitation to join a room, the invitee's If a user has received and accepted an invitation to join a room, the invitee's
home server can now send an invite acceptance message to a chosen candidate homeserver can now send an invite acceptance message to a chosen candidate
server from the list given in the invitation, citing also the PDU ID of the server from the list given in the invitation, citing also the PDU ID of the
invitation as "proof" of their invite. (This is required as due to late message invitation as "proof" of their invite. (This is required as due to late message
propagation it could be the case that the acceptance is received before the propagation it could be the case that the acceptance is received before the
@ -85,7 +85,7 @@ can instead post a "knock" message, which informs other members of the room that
the would-be joiner wishes to become a member and sets their membership value to the would-be joiner wishes to become a member and sets their membership value to
"knocked". If any of them wish to accept this, they can then send an invitation "knocked". If any of them wish to accept this, they can then send an invitation
in the usual way described above. Knowing that the user has already knocked and in the usual way described above. Knowing that the user has already knocked and
expressed an interest in joining, the invited user's home server should expressed an interest in joining, the invited user's homeserver should
immediately accept that invitation on the user's behalf, and go on to join the immediately accept that invitation on the user's behalf, and go on to join the
room in the usual way. room in the usual way.

@ -18,19 +18,19 @@ users, and other management and miscellaneous metadata), and a message history.
Room Identity and Naming Room Identity and Naming
======================== ========================
Rooms can be arbitrarily created by any user on any home server; at which point Rooms can be arbitrarily created by any user on any homeserver; at which point
the home server will sign the message that creates the channel, and the the homeserver will sign the message that creates the channel, and the
fingerprint of this signature becomes the strong persistent identify of the fingerprint of this signature becomes the strong persistent identify of the
room. This now identifies the room to any home server in the network regardless room. This now identifies the room to any homeserver in the network regardless
of its original origin. This allows the identify of the room to outlive any of its original origin. This allows the identify of the room to outlive any
particular server. Subject to appropriate permissions [to be discussed later], particular server. Subject to appropriate permissions [to be discussed later],
any current member of a room can invite others to join it, can post messages any current member of a room can invite others to join it, can post messages
that become part of its history, and can change the persistent state of the room that become part of its history, and can change the persistent state of the room
(including its current set of permissions). (including its current set of permissions).
Home servers can provide a directory service, allowing a lookup from a Homeservers can provide a directory service, allowing a lookup from a
convenient human-readable form of room label to a room ID. This mapping is convenient human-readable form of room label to a room ID. This mapping is
scoped to the particular home server domain and so simply represents that server scoped to the particular homeserver domain and so simply represents that server
administrator's opinion of what room should take that label; it does not have to administrator's opinion of what room should take that label; it does not have to
be globally replicated and does not form part of the stored state of that room. be globally replicated and does not form part of the stored state of that room.
@ -156,7 +156,7 @@ m.public_history
to be a member of the room. to be a member of the room.
m.archive_servers m.archive_servers
For "public" rooms with public history, gives a list of home servers that For "public" rooms with public history, gives a list of homeservers that
should be included in message distribution to the room, even if no users on should be included in message distribution to the room, even if no users on
that server are present. These ensure that a public room can still persist that server are present. These ensure that a public room can still persist
even if no users are currently members of it. This list should be consulted by even if no users are currently members of it. This list should be consulted by
@ -179,7 +179,7 @@ m.topic
Room Creation Templates Room Creation Templates
======================= =======================
A client (or maybe home server?) could offer a few templates for the creation of A client (or maybe homeserver?) could offer a few templates for the creation of
new rooms. For example, for a simple private one-to-one chat the channel could new rooms. For example, for a simple private one-to-one chat the channel could
assign the creator a power-level of 1, requiring a level of 1 to invite, and assign the creator a power-level of 1, requiring a level of 1 to invite, and
needing an invite before members can join. An invite is then sent to the other needing an invite before members can join. An invite is then sent to the other
@ -215,7 +215,7 @@ permissions to allow this direct messaging.
Between any given pair of user IDs that wish to exchange private messages, there Between any given pair of user IDs that wish to exchange private messages, there
will exist a single shared Room, created lazily by either side. These rooms will will exist a single shared Room, created lazily by either side. These rooms will
need a certain amount of special handling in both home servers and display on need a certain amount of special handling in both homeservers and display on
clients, but as much as possible should be treated by the lower layers of code clients, but as much as possible should be treated by the lower layers of code
the same as other rooms. the same as other rooms.
@ -226,7 +226,7 @@ clients should display these in a special way too as the room name is not
important; instead it should distinguish them on the Display Name of the other important; instead it should distinguish them on the Display Name of the other
party. party.
Home Servers will need a client-API option to request setting up a new user-user Homeservers will need a client-API option to request setting up a new user-user
chat room, which will then need special handling within the server. It will chat room, which will then need special handling within the server. It will
create a new room with the following create a new room with the following
@ -260,7 +260,7 @@ history with each other simultaneously create a room and invite the other to it.
This is called a "glare" situation. There are two possible ideas for how to This is called a "glare" situation. There are two possible ideas for how to
resolve this: resolve this:
* Each Home Server should persist the mapping of (user ID pair) to room ID, so * Each homeserver should persist the mapping of (user ID pair) to room ID, so
that duplicate requests can be suppressed. On receipt of a room creation that duplicate requests can be suppressed. On receipt of a room creation
request that the HS thinks there already exists a room for, the invitation to request that the HS thinks there already exists a room for, the invitation to
join can be rejected if: join can be rejected if:

@ -66,7 +66,7 @@ Privacy
A User may publish the association between their phone number and Matrix User ID A User may publish the association between their phone number and Matrix User ID
on the Identity Server without publishing the number in their Profile hosted on on the Identity Server without publishing the number in their Profile hosted on
their Home Server. their homeserver.
Identity Servers should refrain from publishing reverse mappings and should Identity Servers should refrain from publishing reverse mappings and should
take steps, such as rate limiting, to prevent attackers enumerating the space of take steps, such as rate limiting, to prevent attackers enumerating the space of

@ -0,0 +1,285 @@
WebSockets API
==============
Introduction
------------
This document is a proposal for a WebSockets-based client-server API. It is not
intended to replace the REST API, but rather to complement it and provide an
alternative interface for certain operations.
The primary goal is to offer a more efficient interface than the REST API: by
using a bidirectional protocol such as WebSockets we can avoid the overheads
involved in long-polling (SSL negotiation, HTTP headers, etc). In doing so we
will reduce the latency between server and client by allowing the server to
send events as soon as they arrive, rather than having to wait for a poll from
the client.
Handshake
---------
1. Instead of calling ``/sync``, the client makes a websocket request to
``/_matrix/client/rN/stream``, passing the query parameters ``access_token``
and ``since``, and optionally ``filter`` - all of which have the same
meaning as for ``/sync``.
* The client sets the ``Sec-WebSocket-Protocol`` to ``m.json``. (Servers may
offer alternative encodings; at present only the JSON encoding is
specified but in future we will specify alternative encodings.)
#. The server returns the websocket handshake; the socket is then connected.
If the server does not return a valid websocket handshake, this indicates that
the server or an intermediate proxy does not support WebSockets. In this case,
the client should fall back to polling the ``/sync`` REST endpoint.
Example
~~~~~~~
Client request:
.. code:: http
GET /_matrix/client/v2_alpha/stream?access_token=123456&since=s72594_4483_1934 HTTP/1.1
Host: matrix.org
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: m.json
Sec-WebSocket-Version: 13
Origin: https://matrix.org
Server response:
.. code:: http
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: m.json
Update Notifications
--------------------
Once the socket is connected, the server begins streaming updates over the
websocket. The server sends Update notifications about new messages or state
changes. To make it easy for clients to parse, Update notifications have the
same structure as the response to ``/sync``: an object with the following
members:
============= ========== ===================================================
Key Type Description
============= ========== ===================================================
next_batch string The batch token to supply in the ``since`` param of
the next /sync request. This is not required for
streaming of events over the WebSocket, but is
provided so that clients can reconnect if the
socket is disconnected.
presence Presence The updates to the presence status of other users.
rooms Rooms Updates to rooms.
============= ========== ===================================================
Example
~~~~~~~
Message from the server:
.. code:: json
{
"next_batch": "s72595_4483_1934",
"presence": {
"events": []
},
"rooms": {
"join": {},
"invite": {},
"leave": {}
}
}
Client-initiated operations
---------------------------
The client can perform certain operations by sending a websocket message to
the server. Such a "Request" message should be a JSON-encoded object with
the following members:
============= ========== ===================================================
Key Type Description
============= ========== ===================================================
id string A unique identifier for this request
method string Specifies the name of the operation to be
performed; see below for available operations
param object The parameters for the requested operation.
============= ========== ===================================================
The server responds to a client Request with a Response message. This is a
JSON-encoded object with the following members:
============= ========== ===================================================
Key Type Description
============= ========== ===================================================
id string The same as the value in the corresponding Request
object. The presence of the ``id`` field
distinguishes a Response message from an Update
notification.
result object On success, the results of the request.
error object On error, an object giving the resons for the
error. This has the same structure as the "standard
error response" for the Matrix API: an object with
the fields ``errcode`` and ``error``.
============= ========== ===================================================
Request methods
~~~~~~~~~~~~~~~
It is not intended that all operations which are available via the REST API
will be available via the WebSockets API, but a few simple, common operations
will be exposed. The initial operations will be as follows.
``ping``
^^^^^^^^
This is a no-op which clients may use to keep their connection alive.
The request ``params`` and the response ``result`` should be empty.
``send``
^^^^^^^^
Send a message event to a room. The parameters are as follows:
============= ========== ===================================================
Parameter Type Description
============= ========== ===================================================
room_id string **Required.** The room to send the event to
event_type string **Required.** The type of event to send.
content object **Required.** The content of the event.
============= ========== ===================================================
The result is as follows:
============= ========== ===================================================
Key Type Description
============= ========== ===================================================
event_id string A unique identifier for the event.
============= ========== ===================================================
The ``id`` from the Request message is used as the transaction ID by the
server.
``state``
^^^^^^^^^
Update the state on a room.
============= ========== ===================================================
Parameter Type Description
============= ========== ===================================================
room_id string **Required.** The room to set the state in
event_type string **Required.** The type of event to send.
state_key string **Required.** The state_key for the state to send.
content object **Required.** The content of the event.
============= ========== ===================================================
The result is as follows:
============= ========== ===================================================
Key Type Description
============= ========== ===================================================
event_id string A unique identifier for the event.
============= ========== ===================================================
Example
~~~~~~~
Client request:
.. code:: json
{
"id": "12345",
"method": "send",
"params": {
"room_id": "!d41d8cd:matrix.org",
"event_type": "m.room.message",
"content": {
"msgtype": "m.text",
"body": "hello"
}
}
}
Server response:
.. code:: json
{
"id": "12345",
"result": {
"event_id": "$66697273743031:matrix.org"
}
}
Alternative server response, in case of error:
.. code:: json
{
"id": "12345",
"error": {
"errcode": "M_MISSING_PARAM",
"error": "Missing parameter: event_type"
}
}
Rationale
---------
Alternatives to WebSockets include HTTP/2, CoAP, and simply rolling our own
protocol over raw TCP sockets. However, the need to implement browser-based
clients essentially reduces our choice to WebSockets. HTTP/2 streams will
probably provide an interesting alternative in the future, but current browsers
do not appear to give javascript applications low-level access to the protocol.
Concerning the continued use of the JSON encoding: we prefer to focus on the
transition to WebSockets initially. Replacing JSON with a compact
representation such as CBOR, MessagePack, or even just compressed JSON will be
a likely extension for the future. The support for negotiation of subprotocols
within WebSockets should make this a simple transition once time permits.
The number of methods available for client requests is deliberately limited, as
each method requires code to be written to map it onto the equivalent REST
implementation. Some REST methods - for instance, user registration and login -
would be pointless to expose via WebSockets. It is likely, however, that we
will increate the number of methods available via the WebSockets API as it
becomes clear which would be most useful.
Open questions
--------------
Throttling
~~~~~~~~~~
At least in v2 sync, clients are inherently self-throttling - if they do not
poll quickly enough, events will be dropped from the next result. This proposal
raises the possibility that events will be produced more quickly than they can
be sent to the client; backlogs will build up on the server and/or in the
intermediate network, which will not only lead to high latency on events being
delivered, but will lead to responses to client requests also being delayed.
We may need to implement some sort of throttling mechanism by which the server
can start to drop events. The difficulty is in knowing when to start dropping
events. A few ideas:
* Use websocket pings to measure the RTT; if it starts to increase, start
dropping events. But this requires knowledge of the base RTT, and a useful
model of what constitutes an excessive increase.
* Have the client acknowledge each batch of events, and use a window to ensure
the number of outstanding batches is limited. This is annoying as it requires
the client to have to acknowledge batches - and it's not clear what the right
window size is: we want a big window for long fat networks (think of mobile
clients), but a small one for one with lower latency.
* Start dropping events if the server's TCP buffer starts filling up. This has
the advantage of delegating the congestion-detection to TCP (which already
has a number of algorithms to deal with it, to greater or lesser
effectiveness), but relies on homeservers being hosted on OSes which use
sensible TCP congestion-avoidance algorithms, and more critically, an ability
to read the fill level of the TCP send buffer.

@ -7,7 +7,7 @@ resolved correctly. For basic CLI testing, we recommend and have verified they
work with the Node.js package [z-schema](https://github.com/zaggino/z-schema): work with the Node.js package [z-schema](https://github.com/zaggino/z-schema):
``` ```
$ npm install -g z-schema $ npm install -g z-schema
$ z-schema schema/v1/m.room.message examples/v1/m.room.message_m.text $ z-schema schema/m.room.message examples/m.room.message_m.text
schema validation passed schema validation passed
json #1 validation passed json #1 validation passed
``` ```

@ -1,22 +0,0 @@
#!/bin/bash -e
# Runs z-schema over all of the schema files (looking for matching examples)
if ! which z-schema; then
echo >&2 "Need to install z-schema; run: sudo npm install -g z-schema"
exit 1
fi
find schema/v1/m.* | while read line
do
split_path=(${line///// })
event_type=(${split_path[2]})
echo "Checking $event_type"
echo "--------------------"
# match exact name or exact name with a #<something>
find examples/v1 -name $event_type -o -name "$event_type#*" | while read exline
do
echo " against $exline"
# run z-schema: because of bash -e if this fails we bail with exit code 1
z-schema schema/v1/$event_type $exline
done
done

@ -1,4 +1,4 @@
#! /usr/bin/env python #!/usr/bin/env python
import sys import sys
import json import json
@ -38,13 +38,12 @@ def check_example_file(examplepath, schemapath):
schema = yaml.load(f) schema = yaml.load(f)
fileurl = "file://" + os.path.abspath(schemapath) fileurl = "file://" + os.path.abspath(schemapath)
schema["id"] = fileurl
resolver = jsonschema.RefResolver(schemapath, schema, handlers={"file": load_yaml})
print ("Checking schema for: %r %r" % (examplepath, schemapath)) print ("Checking schema for: %r %r" % (examplepath, schemapath))
# Setting the 'id' tells jsonschema where the file is so that it
# can correctly resolve relative $ref references in the schema
schema['id'] = fileurl
try: try:
jsonschema.validate(example, schema) jsonschema.validate(example, schema, resolver=resolver)
except Exception as e: except Exception as e:
raise ValueError("Error validating JSON schema for %r %r" % ( raise ValueError("Error validating JSON schema for %r %r" % (
examplepath, schemapath examplepath, schemapath
@ -60,6 +59,8 @@ def check_example_dir(exampledir, schemadir):
continue continue
examplepath = os.path.join(root, filename) examplepath = os.path.join(root, filename)
schemapath = examplepath.replace(exampledir, schemadir) schemapath = examplepath.replace(exampledir, schemadir)
if schemapath.find("#") >= 0:
schemapath = schemapath[:schemapath.find("#")]
try: try:
check_example_file(examplepath, schemapath) check_example_file(examplepath, schemapath)
except Exception as e: except Exception as e:
@ -69,6 +70,15 @@ def check_example_dir(exampledir, schemadir):
if errors: if errors:
raise ValueError("Error validating examples") raise ValueError("Error validating examples")
def load_yaml(path):
if not path.startswith("file:///"):
raise Exception("Bad ref: %s" % (path,))
path = path[len("file://"):]
with open(path, "r") as f:
return yaml.load(f)
if __name__ == '__main__': if __name__ == '__main__':
try: try:
check_example_dir("examples", "schema") check_example_dir("examples", "schema")

@ -13,5 +13,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.call.answer", "type": "m.call.answer",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -15,5 +15,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.call.candidates", "type": "m.call.candidates",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -8,5 +8,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.call.hangup", "type": "m.call.hangup",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -13,5 +13,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.call.invite", "type": "m.call.invite",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -8,5 +8,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.room.aliases", "type": "m.room.aliases",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -14,5 +14,5 @@
"type": "m.room.avatar", "type": "m.room.avatar",
"state_key": "", "state_key": "",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -8,5 +8,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.room.canonical_alias", "type": "m.room.canonical_alias",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -8,5 +8,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.room.create", "type": "m.room.create",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -0,0 +1,12 @@
{
"age": 242353,
"content": {
"guest_access": "can_join"
},
"state_key": "",
"origin_server_ts": 1431961217938,
"event_id": "$WLGTSEFSEG:localhost",
"type": "m.room.guest_access",
"room_id": "!Cuyf34gef24u:localhost",
"sender": "@example:localhost"
}

@ -8,5 +8,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.room.history_visibility", "type": "m.room.history_visibility",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

@ -8,5 +8,5 @@
"event_id": "$WLGTSEFSEF:localhost", "event_id": "$WLGTSEFSEF:localhost",
"type": "m.room.join_rules", "type": "m.room.join_rules",
"room_id": "!Cuyf34gef24t:localhost", "room_id": "!Cuyf34gef24t:localhost",
"user_id": "@example:localhost" "sender": "@example:localhost"
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save