openapi: 3.0.0
info:
  title: Maubot Management
  version: 0.1.0
  description: The API to manage a [maubot](https://github.com/maubot/maubot) instance
  license:
    name: GNU Affero General Public License version 3
    url: 'https://github.com/maubot/maubot/blob/master/LICENSE'
security:
- bearer: []
servers:
- url: /_matrix/maubot/v1

paths:
  /auth/login:
    post:
      operationId: login
      summary: Log in with the unshared secret or username+password
      tags: [Authentication]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: Set either username+password or secret.
              properties:
                secret:
                  type: string
                  description: The unshared server secret for root login
                username:
                  type: string
                  description: The username for normal login
                password:
                  type: string
                  description: The password for normal login
      responses:
        200:
          description: Logged in successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
        401:
          description: Invalid credentials
  /auth/ping:
    post:
      operationId: ping
      summary: Check if the given token is valid
      tags: [Authentication]
      responses:
        200:
          description: Token is OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  username:
                    type: string
        401:
          description: Token is not OK

  /plugins:
    get:
      operationId: get_plugins
      summary: Get the list of installed plugins
      tags: [Plugins]
      responses:
        200:
          description: The list of plugins
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Plugin'
        401:
          $ref: '#/components/responses/Unauthorized'
  /plugins/upload:
    post:
      operationId: upload_plugin
      summary: Upload a new plugin
      description: Upload a new plugin. If the plugin already exists, enabled instances will be restarted.
      tags: [Plugins]
      parameters:
      - name: allow_override
        in: query
        description: Set to allow overriding existing plugins
        required: false
        schema:
          type: boolean
          default: false
      requestBody:
        content:
          application/zip:
            schema:
              type: string
              format: binary
              example: The plugin maubot archive (.mbp)
      responses:
        200:
          description: Plugin uploaded and replaced current version successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plugin'
        201:
          description: New plugin uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plugin'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/Unauthorized'
        409:
          description: Plugin already exists and allow_override was not specified.
  '/plugin/{id}':
    parameters:
    - name: id
      in: path
      description: The ID of the plugin to get
      required: true
      schema:
        type: string
    get:
      operationId: get_plugin
      summary: Get information about a specific plugin
      tags: [Plugins]
      responses:
        200:
          description: Plugin found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plugin'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/PluginNotFound'
    delete:
      operationId: delete_plugin
      summary: Delete a plugin
      description: Delete a plugin. All instances of the plugin must be deleted before deleting the plugin.
      tags: [Plugins]
      responses:
        204:
          description: Plugin deleted
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/PluginNotFound'
        412:
          description: One or more plugin instances of this type exist
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      operationId: put_plugin
      summary: Upload a new or replacement plugin
      description: |
        Upload a new or replacement plugin with the specified ID.
        A HTTP 400 will be returned if the ID of the uploaded plugin
        doesn't match the ID in the path. If the plugin already
        exists, enabled instances will be restarted.
      tags: [Plugins]
      requestBody:
        content:
          application/zip:
            schema:
              type: string
              format: binary
              example: The plugin maubot archive (.mbp)
      responses:
        200:
          description: Plugin uploaded and replaced current version successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plugin'
        201:
          description: New plugin uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plugin'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/Unauthorized'
  /plugin/{id}/reload:
    parameters:
    - name: id
      in: path
      description: The ID of the plugin to get
      required: true
      schema:
        type: string
    post:
      operationId: reload_plugin
      summary: Reload a plugin from disk
      tags: [Plugins]
      responses:
        200:
          description: Plugin reloaded
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/PluginNotFound'

  /instances:
    get:
      operationId: get_instances
      summary: Get all plugin instances
      tags: [Plugin instances]
      responses:
        200:
          description: The list of instances
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PluginInstance'
        401:
          $ref: '#/components/responses/Unauthorized'
  '/instance/{id}':
    parameters:
    - name: id
      in: path
      description: The ID of the instance to get
      required: true
      schema:
        type: string
    get:
      operationId: get_instance
      summary: Get information about a specific plugin instance
      tags: [Plugin instances]
      responses:
        200:
          description: Plugin instance found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PluginInstance'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/InstanceNotFound'
    delete:
      operationId: delete_instance
      summary: Delete a specific plugin instance
      tags: [Plugin instances]
      responses:
        204:
          description: Plugin instance deleted
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/InstanceNotFound'
    put:
      operationId: update_instance
      summary: Create a plugin instance or edit the details of an existing plugin instance
      tags: [Plugin instances]
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PluginInstance'
      responses:
        200:
          description: Plugin instance edited
        201:
          description: Plugin instance created
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          description: The referenced client or plugin type could not be found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  '/clients':
    get:
      operationId: get_clients
      summary: Get the list of Matrix clients
      tags: [Clients]
      responses:
        200:
          description: The list of plugins
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MatrixClient'
        401:
          $ref: '#/components/responses/Unauthorized'
  /client/new:
    post:
      operationId: create_client
      summary: Create a Matrix client
      tags: [Clients]
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatrixClient'
      responses:
        201:
          description: Client created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/ClientNotFound'
        409:
          description: There is already a client with the user ID of that token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  '/client/{id}':
    parameters:
    - name: id
      in: path
      description: The Matrix user ID of the client to get
      required: true
      schema:
        type: string
    get:
      operationId: get_client
      summary: Get information about a specific Matrix client
      tags: [Clients]
      responses:
        200:
          description: Client found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/ClientNotFound'
    put:
      operationId: update_client
      summary: Create or update a Matrix client
      tags: [Clients]
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatrixClient'
      responses:
        202:
          description: Client updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        201:
          description: Client created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/Unauthorized'
    delete:
      operationId: delete_client
      summary: Delete a Matrix client
      tags: [Clients]
      responses:
        204:
          description: Client deleted
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/ClientNotFound'
        412:
          description: One or more plugin instances with this as their primary client exist
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  '/client/{id}/clearcache':
    parameters:
    - name: id
      in: path
      description: The Matrix user ID of the client to change
      required: true
      schema:
        type: string
    put:
      operationId: clear_client_cache
      summary: Clear the sync/state cache of a Matrix client
      tags: [Clients]
      responses:
        200:
          description: Cache cleared
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/ClientNotFound'
  /client/auth/servers:
    get:
      operationId: get_client_auth_servers
      summary: Get the list of servers you can register or log in on via the maubot server
      tags: [Clients]
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                description: Key-value map from server name to homeserver URL
                additionalProperties:
                  type: string
                  description: The homeserver URL
                example:
                  maunium.net: https://maunium.net
                  example.com: https://matrix.example.org
        401:
          $ref: '#/components/responses/Unauthorized'
  '/client/auth/{server}/register':
    parameters:
    - name: server
      in: path
      description: The server name to register the account on.
      required: true
      schema:
        type: string
    - name: update_client
      in: query
      description: Should maubot store the access details in a Client instead of returning them?
      required: false
      schema:
        type: boolean
    post:
      operationId: client_auth_register
      summary: |
        Register a new account on the given Matrix server using the shared registration
        secret configured into the maubot server.
      tags: [Clients]
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatrixAuthentication'
      responses:
        200:
          description: Registration successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                    example: syt_123_456_789
                  user_id:
                    type: string
                    example: '@putkiteippi:maunium.net'
                  device_id:
                    type: string
                    example: maubot_F00BAR12
        201:
          description: Client created (when update_client is true)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        401:
          $ref: '#/components/responses/Unauthorized'
        409:
          description: |
            There is already a client with the user ID of that token.
            This should usually not happen, because the user ID was just created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        500:
          $ref: '#/components/responses/MatrixServerError'
  '/client/auth/{server}/login':
    parameters:
    - name: server
      in: path
      description: The server name to log in to.
      required: true
      schema:
        type: string
    - name: update_client
      in: query
      description: Should maubot store the access details in a Client instead of returning them?
      required: false
      schema:
        type: boolean
    post:
      operationId: client_auth_login
      summary: Log in to the given Matrix server via the maubot server
      tags: [Clients]
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatrixAuthentication'
      responses:
        200:
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  user_id:
                    type: string
                    example: '@putkiteippi:maunium.net'
                  access_token:
                    type: string
                    example: syt_123_456_789
                  device_id:
                    type: string
                    example: maubot_F00BAR12
        201:
          description: Client created (when update_client is true)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        202:
          description: Client updated (when update_client is true)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatrixClient'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/MatrixServerError'

components:
  responses:
    Unauthorized:
      description: Invalid or missing access token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    PluginNotFound:
      description: Plugin not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ClientNotFound:
      description: Client not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InstanceNotFound:
      description: Plugin instance not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadRequest:
      description: Bad request (e.g. bad request body)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    MatrixServerError:
      description: The Matrix server returned an error
      content:
        application/json:
          schema:
            type: object
            properties:
              errcode:
                type: string
                description: The `errcode` returned by the server.
              error:
                type: string
                description: The human-readable error returned by the server.
              http_status:
                type: integer
                description: The HTTP status returned by the server.

  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: Required authentication for all endpoints
  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: A human-readable error message
        errcode:
          type: string
          description: A simple error code
    Plugin:
      type: object
      properties:
        id:
          type: string
          example: xyz.maubot.jesaribot
        version:
          type: string
          example: 2.0.0
        instances:
          type: array
          items:
            $ref: '#/components/schemas/PluginInstance'
    PluginInstance:
      type: object
      properties:
        id:
          type: string
          example: jesaribot
        type:
          type: string
          example: xyz.maubot.jesaribot
        enabled:
          type: boolean
          example: true
        started:
          type: boolean
          example: true
        primary_user:
          type: string
          example: '@putkiteippi:maunium.net'
        config:
          type: string
          example: "YAML"
    MatrixClient:
      type: object
      properties:
        id:
          type: string
          example: '@putkiteippi:maunium.net'
          readOnly: true
          description: The Matrix user ID of this client.
        homeserver:
          type: string
          example: 'https://maunium.net'
          description: The homeserver URL for this client.
        access_token:
          type: string
          description: The Matrix access token for this client.
        device_id:
          type: string
          description: The Matrix device ID corresponding to the access token.
        fingerprint:
          type: string
          description: The encryption device fingerprint for verification.
        enabled:
          type: boolean
          example: true
          description: Whether or not this client is enabled.
        started:
          type: boolean
          example: true
          description: Whether or not this client and its instances have been started.
        sync:
          type: boolean
          example: true
          description: Whether or not syncing is enabled on this client.
        sync_ok:
          type: boolean
          example: true
          description: Whether or not the previous sync was successful on this client.
        autojoin:
          type: boolean
          example: true
          description: Whether or not this client should automatically join rooms when invited.
        displayname:
          type: string
          example: J. E. Saarinen
          description: The display name for this client.
        avatar_url:
          type: string
          example: 'mxc://maunium.net/FsPQQTntCCqhJMFtwArmJdaU'
          description: The content URI of the avatar for this client.
        instances:
          type: array
          readOnly: true
          items:
            $ref: '#/components/schemas/PluginInstance'
    MatrixAuthentication:
      type: object
      properties:
        username:
          type: string
          example: putkiteippi
          description: The user ID localpart to register/log in as.
        password:
          type: string
          example: p455w0rd
          description: The password for/of the user.
