End-to-End Encryption API

Key Upload

POST /_matrix/client/v3/keys/upload

Upload device keys and one-time keys (OTK):

{
  "device_keys": {
    "user_id": "@alice:localhost",
    "device_id": "ABCDEF",
    "algorithms": [
      "m.olm.v1.curve25519-aes-sha2",
      "m.megolm.v1.aes-sha2"
    ],
    "keys": {
      "curve25519:ABCDEF": "...",
      "ed25519:ABCDEF": "..."
    }
  },
  "one_time_keys": {
    "signed_curve25519:AAAAAA": { ... },
    "signed_curve25519:AAAAAB": { ... }
  }
}

Response:

{
  "one_time_key_counts": {
    "signed_curve25519": 50
  }
}

Key Query

POST /_matrix/client/v3/keys/query
{
  "device_keys": {
    "@bob:localhost": ["DEVICE1", "DEVICE2"]
  },
  "timeout": 10000
}

Returns device keys for the specified users/devices.

Key Claim

POST /_matrix/client/v3/keys/claim
{
  "one_time_keys": {
    "@bob:localhost": {
      "DEVICE1": "signed_curve25519"
    }
  },
  "timeout": 10000
}

Claims one-time keys for Olm session establishment.

Key Changes

GET /_matrix/client/v3/changes

Returns a list of users whose device keys have changed since the given token.

Cross-Signing Keys

Upload Master Key

POST /_matrix/client/v3/keys/device_signing/upload

Upload cross-signing keys (master, self-signing, user-signing):

{
  "master_keys": {
    "@alice:localhost": {
      "algorithms": ["ed25519"],
      "keys": { "ed25519:MASTER_KEY_ID": "..." }
    }
  },
  "self_signing_keys": { ... },
  "user_signing_keys": { ... }
}

Device Management

List Devices

GET /_matrix/client/v3/devices

Get Device

GET /_matrix/client/v3/devices/{deviceId}

Update Device

PUT /_matrix/client/v3/devices/{deviceId}
{ "display_name": "Element Web" }

Delete Devices

POST /_matrix/client/v3/delete_devices
{
  "auth": {
    "type": "m.login.password",
    "identifier": { "type": "m.id.user", "user": "alice" },
    "password": "secret123"
  }
}

To-Device Messages

PUT /_matrix/client/v3/sendToDevice/{eventType}/{txnId}
{
  "messages": {
    "@bob:localhost": {
      "DEVICE1": { ... }
    }
  }
}

To-device messages are delivered via /sync in the to_device section. Each message must include an event_id field for E2EE clients like Cinny to process room key exchanges correctly.

Device Key Visibility

When a user joins, leaves, or is banned from a room, RoomEventService.upsertMembership() triggers device_lists.changed / device_lists.left notifications in the /sync response. This allows clients to track which devices need encryption key updates.