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¶
- 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}'
- 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 behavior
- When
allow_roomsis 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.