Skip to content

Matrix Channel

Overview

The Matrix channel receives messages via long-polling the /sync endpoint and sends replies via the REST API. No public endpoint is required, making it suitable for deployment behind firewalls or on internal networks. Matrix is a decentralized open communication protocol that supports self-hosted homeservers (e.g., Synapse, Dendrite).

This channel supports realtime streaming output (is_realtime=True) — tokens generated by the agent can be incrementally pushed to the room.

Configuration Example

channels:
  matrix:
    enabled: true
    homeserver: https://matrix.example.com
    user_id: "@echo-bot:example.com"
    access_token: ${MATRIX_ACCESS_TOKEN}
    allow_rooms:
      - "!abcdef123456:example.com"
      - "!support-room:example.com"
Field Type Default Description
homeserver string Homeserver URL (including protocol)
user_id string Bot's full Matrix ID
access_token string Bearer access token
allow_rooms list [] Room ID allowlist; empty responds in all joined rooms

Credentials

Creating a Bot Account

  1. Register a new user on the homeserver as a bot:
# Register via Synapse admin API (requires admin privileges)
curl -X POST "https://matrix.example.com/_synapse/admin/v1/register" \
  -H "Authorization: Bearer <admin_token>" \
  -H "Content-Type: application/json" \
  -d '{"nonce": "...", "username": "echo-bot", "password": "secure-password", "admin": false}'
  1. Alternatively, create an account through the standard client registration flow.

Obtaining an Access Token

Option 1: Via Login API

curl -X POST "https://matrix.example.com/_matrix/client/v3/login" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "m.login.password",
    "identifier": {"type": "m.id.user", "user": "echo-bot"},
    "password": "secure-password"
  }'

The access_token field in the response is the token you need.

Option 2: Via Admin Panel

Some homeserver admin panels (e.g., Synapse Admin UI) can generate long-lived tokens for users directly.

Token Security

An access token grants full account privileges. Store it securely, never commit it to version control, and inject it via environment variables.

Inviting the Bot to Rooms

# Invite the bot to a target room
curl -X POST "https://matrix.example.com/_matrix/client/v3/rooms/!roomid:example.com/invite" \
  -H "Authorization: Bearer <your_token>" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "@echo-bot:example.com"}'

The bot will automatically accept invitations (auto-join) when it starts.

Capability Matrix

Capability Supported Notes
Edit sent messages No m.replace not implemented in current version
Reactions Yes Supports m.reaction events
File attachments No Media messages not processed
Realtime streaming Yes Streaming via incremental message edits
Group / multi-party Yes Native multi-user support via rooms
Voice messages Yes Supports receiving voice message events
Polls Yes Supports Matrix poll events

Internal Mechanics

Sync Checkpoint Persistence

The channel uses the since token from the Matrix /sync response as a checkpoint. This token is persisted to disk, ensuring:

  • Sync resumes from the last position after process restart, with no missed messages
  • No duplicate processing of already-seen events

Room Allowlist Isolation

allow_rooms:
  - "!abcdef123456:example.com"

allow_rooms behavior

  • When allow_rooms is configured, the bot only responds to messages in listed rooms
  • When empty or omitted, the bot responds in all joined rooms
  • The bot will still join rooms it is invited to, but will not reply in rooms outside the allowlist

FAQ

Bot was invited to a room but doesn't respond?

Check the allow_rooms configuration. If an allowlist is set but doesn't include that room ID, the bot will join but not reply. Add the room ID to the allowlist or clear allow_rooms.

How do I get a room ID?

In clients like Element, go to Room Settings → Advanced → "Internal room ID". The format is !randomstring:server.name.

What happens on sync timeout or disconnection?

The channel has built-in retry logic. After a network interruption, it automatically reconnects and resumes from the last since token. No manual intervention needed.

Encrypted rooms are not supported

The channel handles unencrypted messages only; there is no Olm / Megolm implementation in the code. Invited into an E2EE room the bot will join, but it cannot decrypt what it receives and therefore will not reply.

To use it where encryption is in play, create a separate unencrypted room — a room's encryption cannot be turned off once enabled.