Guide 16

Matrix bots: the Client-Server API, end-to-end encryption and application services

Matrix has no central bot platform. A bot is simply a Matrix client, which gives you full control and a few extra responsibilities.

Guide2 min readUpdated

The model

Matrix is an open standard for federated real-time communication. Users live on homeservers (for example Synapse, Dendrite or Conduit) that federate with each other. A bot is a normal user account that talks to its homeserver through the Client-Server API.

  • User IDs look like @helper:example.org. Check local part rules with the username validator.
  • Rooms have IDs like !abc123:example.org and optional aliases like #support:example.org.
  • Everything in a room is an event: messages, membership changes, state.

Getting a token

Register a dedicated account for the bot, then log in once with POST /_matrix/client/v3/login and store the returned access token as a secret. Avoid logging in on every start: each login creates a new device, which matters for encryption.

Receiving events

Call GET /_matrix/client/v3/sync in a loop with a timeout (long polling) and pass the next_batch token as since on the next call. Persist that token so a restart does not replay or miss history. Use a filter to receive only the event types you need.

Sending messages

PUT /_matrix/client/v3/rooms/{roomId}/send/m.room.message/{txnId}
Authorization: Bearer <token>

{"msgtype": "m.text", "body": "Hello", "format": "org.matrix.custom.html", "formatted_body": "<b>Hello</b>"}

The transaction ID makes the request idempotent: retrying with the same txnId will not duplicate the message. Use m.notice as msgtype for automated replies; clients may display notices differently and other bots conventionally do not respond to them, which prevents bot loops.

Invites and permissions

Bots usually auto-join rooms they are invited to. Limit this to trusted servers or users, or anyone can pull your bot into spam rooms. Room power levels decide whether the bot can kick, redact or change state.

Encryption

Many rooms are end-to-end encrypted. To read them a bot needs an Olm/Megolm implementation, persistent device keys and a crypto store. SDKs such as matrix-bot-sdk, matrix-nio (Python), mautrix (Go and Python) or the matrix-rust-sdk handle this. Back up the crypto store; losing it means losing access to encrypted history.

Application services

For bridges or bots that need many virtual users, register an application service with the homeserver. It receives events pushed by the server for namespaces it owns and is not rate limited like a client. It requires access to the homeserver configuration, so it suits self-hosted setups.

Checklist

  • Persist the sync token and the device and crypto store.
  • Send m.notice and ignore notices and your own events.
  • Restrict auto-join and respect rate limit responses (M_LIMIT_EXCEEDED with retry_after_ms).

Check your understanding

1. Why send automated replies as m.notice?
2. What makes a send request idempotent?