---
allOf:
  - $ref: core-event-schema/state_event.yaml
description: |-
  Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (`/rooms/<room id>/invite` etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying to force this state change directly will fail.

  The following membership states are specified:

  - `invite` - The user has been invited to join a room, but has not yet joined it. They may not participate in the room until they join.

  - `join` - The user has joined the room (possibly after accepting an invite), and may participate in it.

  - `leave` - The user was once joined to the room, but has since left (possibly by choice, or possibly by being kicked).

  - `ban` - The user has been banned from the room, and is no longer allowed to join it until they are un-banned from the room (by having their membership state set to a value other than `ban`).

  - `knock` - The user has knocked on the room, requesting permission to participate. They may not participate in the room until they join.

  The `third_party_invite` property will be set if this invite is an `invite` event and is the successor of an `m.room.third_party_invite` event, and absent otherwise.

  This event may also include an `invite_room_state` key inside the event's `unsigned` data.
  If present, this contains an array of [stripped state events](/client-server-api/#stripped-state)
  to assist the receiver in identifying the room.

  The user for which a membership applies is represented by the `state_key`. Under some conditions,
  the `sender` and `state_key` may not match - this may be interpreted as the `sender` affecting
  the membership state of the `state_key` user.

  The `membership` for a given user can change over time. The table below represents the various changes
  over time and how clients and servers must interpret those changes. Previous membership can be retrieved
  from the `prev_content` object on an event. If not present, the user's previous membership must be assumed
  as `leave`.

  |                   | to `invite`          | to `join`                              | to `leave`                                                                                                                              | to `ban`                    | to `knock`           |
  |-------------------|----------------------|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------------|
  | **from `invite`** | No change.           | User joined the room.                  | If the `state_key` is the same as the `sender`, the user rejected the invite. Otherwise, the `state_key` user had their invite revoked. | User was banned.            | User is re-knocking. |
  | **from `join`**   | Must never happen.   | `displayname` or `avatar_url` changed. | If the `state_key` is the same as the `sender`, the user left. Otherwise, the `state_key` user was kicked.                              | User was kicked and banned. | Must never happen.   |
  | **from `leave`**  | New invitation sent. | User joined.                           | No change.                                                                                                                              | User was banned.            | User is knocking.    |
  | **from `ban`**    | Must never happen.   | Must never happen.                     | User was unbanned.                                                                                                                      | No change.                  | Must never happen.   |
  | **from `knock`**  | Knock accepted.      | Must never happen.                     | If the `state_key` is the same as the `sender`, the user retracted the knock. Otherwise, the `state_key` user had their knock denied.   | User was banned.            | No change.           |

properties:
  content:
    properties:
      avatar_url:
        description: 'The avatar URL for this user, if any.'
        type: string
        format: uri
      displayname:
        description: 'The display name for this user, if any.'
        type:
          - "string"
          - "null"
      membership:
        description: The membership state of the user.
        enum:
          - invite
          - join
          - knock
          - leave
          - ban
        type: string
      is_direct:
        description: Flag indicating if the room containing this event was created with the intention of being a direct chat. See [Direct Messaging](/client-server-api/#direct-messaging).
        type: boolean
      join_authorised_via_users_server:
        x-addedInMatrixVersion: "1.2"
        type: string
        description: |-
          Usually found on `join` events, this field is used to denote which homeserver (through representation of a user with sufficient power level)
          authorised the user's join. More information about this field can be found in the [Restricted Rooms Specification](#restricted-rooms).

          Client and server implementations should be aware of the [signing implications](/rooms/v8/#authorization-rules) of including this
          field in further events: in particular, the event must be signed by the server which
          owns the user ID in the field. When copying the membership event's `content`
          (for profile updates and similar) it is therefore encouraged to exclude this
          field in the copy, as otherwise the event might fail event authorization.
      reason:
        x-addedInMatrixVersion: "1.1"
        type: string
        description: |-
          Optional user-supplied text for why their membership has changed. For kicks and bans, this is typically the reason for the kick or ban.
          For other membership changes, this is a way for the user to communicate their intent without having to send a message to the room, such
          as in a case where Bob rejects an invite from Alice about an upcoming concert, but can't make it that day.

          Clients are not recommended to show this reason to users when receiving an invite due to the potential for spam and abuse. Hiding the
          reason behind a button or other component is recommended.
      third_party_invite:
        properties:
          display_name:
            description: A name which can be displayed to represent the user instead of their third party identifier
            type: string
          signed:
            description: 'A block of content which has been signed, which servers can use to verify the event. Clients should ignore this.'
            properties:
              mxid:
                description: The invited matrix user ID. Must be equal to the user_id property of the event.
                type: string
              signatures:
                description: 'A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API.'
                title: Signatures
                type: object
                additionalProperties:
                  type: object
                  additionalProperties:
                    type: string
              token:
                description: The token property of the containing third_party_invite object.
                type: string
            required:
              - mxid
              - signatures
              - token
            title: signed
            type: object
        required:
          - display_name
          - signed
        title: Invite
        type: object
    required:
      - membership
    title: EventContent
    type: object
  state_key:
    description: |-
      The `user_id` this membership event relates to. In all cases except for when `membership` is
      `join`, the user ID sending the event does not need to match the user ID in the `state_key`,
      unlike other events. Regular authorisation rules still apply.
    type: string
  type:
    enum:
      - m.room.member
    type: string
  unsigned:
    allOf:
      - $ref: "core-event-schema/unsigned_prop.yaml"
      - type: object
        properties:
          invite_room_state:
            description: |-
              A subset of the state of the room at the time of the invite, if `membership` is `invite`.
              Note that this state is informational, and SHOULD NOT be trusted; once the client has
              joined the room, it SHOULD fetch the live state from the server and discard the
              invite_room_state. Also, clients must not rely on any particular state being present here;
              they SHOULD behave properly (with possibly a degraded but not a broken experience) in
              the absence of any particular events here. If they are set on the room, at least the
              state for `m.room.avatar`, `m.room.canonical_alias`, `m.room.join_rules`, and `m.room.name`
              SHOULD be included.
            items:
              $ref: "core-event-schema/stripped_state.yaml"
            type: array
          knock_room_state:
            description: |-
              A subset of the state of the room at the time of the knock, if `membership` is `knock`.
              This has the same restrictions as `invite_room_state`. If they are set on the room, at least
              the state for `m.room.avatar`, `m.room.canonical_alias`, `m.room.join_rules`, `m.room.name`,
              and `m.room.encryption` SHOULD be included.
            items:
              $ref: "core-event-schema/stripped_state.yaml"
            type: array
title: The current membership state of a user in the room.
type: object
