Matrix E2EE relay bot for n8n workflows
  • TypeScript 96.4%
  • Just 1.3%
  • JavaScript 1.3%
  • Dockerfile 1%
Find a file
2026-06-08 18:03:37 +00:00
bot fix: harden media config + download per review 2026-06-08 19:25:46 +02:00
docs/superpowers docs: add Matrix media send implementation plan 2026-06-08 19:13:51 +02:00
scripts chore: initial commit of existing codebase before relay bot implementation 2026-06-03 20:59:44 +02:00
workflows Rename project to n8n Matrix Bridge 2026-06-04 09:36:39 +02:00
.gitignore Release v0.6.0 2026-06-08 19:59:24 +02:00
CLAUDE.md docs: document media /send payload mode in CLAUDE.md 2026-06-08 19:30:35 +02:00
docker-compose.yml Prepare 0.4.0 release 2026-06-04 10:40:44 +02:00
Justfile Rename project to n8n Matrix Bridge 2026-06-04 09:36:39 +02:00
package-lock.json Release v0.6.0 2026-06-08 19:59:24 +02:00
package.json Release v0.6.0 2026-06-08 19:59:24 +02:00
README.md Document send request body 2026-06-05 10:56:39 +02:00

n8n Matrix Bridge

Matrix E2EE relay bot for n8n. It listens to encrypted Matrix rooms, detects mentions of the bot, forwards the mention payload to an n8n Webhook, and lets n8n send encrypted replies back through a local /send endpoint.

n8n does not need Matrix credentials or custom nodes; it only uses built-in Webhook and HTTP Request nodes.

Quickstart

  1. Create a dedicated Matrix bot user/device and get an access token.

  2. Invite the bot to the encrypted Matrix rooms you want to bridge.

  3. Import the reference n8n workflow:

    workflows/matrix-mention.json
    

Docker Compose

  1. Create the environment file:

    cp bot/.env.example .env
    
  2. Edit .env and set your Matrix credentials plus a strong BOT_SEND_TOKEN.

  3. Start n8n and the bot:

    docker compose up -d
    
  4. Open n8n at:

    http://localhost:5678
    
  5. In Matrix, mention the bot. n8n should receive the webhook payload and can reply through http://bot:8080/send.

Without Docker

  1. Install and build the bot:

    cd bot
    npm install
    npm run build
    cd ..
    
  2. Set the required environment variables. For example:

    export MATRIX_HOMESERVER_URL='https://matrix.org'
    export MATRIX_ACCESS_TOKEN='syt_xxxx'
    export MATRIX_BOT_USER_ID='@mybot:matrix.org'
    export MATRIX_STORAGE_DIR='./bot-storage'
    export N8N_WEBHOOK_URL='http://localhost:5678/webhook/matrix-mention'
    export BOT_SEND_TOKEN='change-me-strong-secret'
    
  3. Start the bot:

    cd bot
    npm start
    
  4. Run n8n separately and point its HTTP Request reply node at the bot:

    http://localhost:8080/send
    

    If n8n runs in Docker while the bot runs on the host, use:

    http://host.docker.internal:8080/send
    
  5. In Matrix, mention the bot. n8n should receive the webhook payload and can reply through /send.

Configuration

Required variables, usually in .env:

MATRIX_HOMESERVER_URL=https://matrix.org
MATRIX_ACCESS_TOKEN=syt_xxxx
MATRIX_BOT_USER_ID=@mybot:matrix.org
MATRIX_STORAGE_DIR=/data/storage
N8N_WEBHOOK_URL=http://n8n:5678/webhook/matrix-mention
BOT_SEND_TOKEN=change-me-strong-secret

Optional variables:

MATRIX_ROOM_ALLOWLIST=!roomid:matrix.org,!other:matrix.org
WEBHOOK_AUTH_TOKEN=n8n-webhook-secret
BOT_SEND_PORT=8080
BOT_SEND_BIND_ADDRESS=127.0.0.1

Notes:

  • MATRIX_STORAGE_DIR stores the bot's crypto database and sync token. Do not delete it unless you intend to reset the bot device.
  • MATRIX_ROOM_ALLOWLIST restricts which rooms can trigger n8n. Leave it unset to allow all rooms the bot is in.
  • If WEBHOOK_AUTH_TOKEN is set, outbound webhook requests include Authorization: Bearer <WEBHOOK_AUTH_TOKEN>.
  • BOT_SEND_BIND_ADDRESS controls where /send listens. It defaults to 127.0.0.1 for host-local only; use 0.0.0.0 to listen on every interface.
  • /send authentication uses the raw token: Authorization: <BOT_SEND_TOKEN>.

n8n

Import workflows/matrix-mention.json or create a workflow with:

  1. Webhook node

    • Method: POST
    • Path: matrix-mention
    • Production URL should match N8N_WEBHOOK_URL.
  2. Your processing nodes.

  3. HTTP Request node to send replies:

    • Method: POST

    • URL when using the provided Docker Compose network:

      http://bot:8080/send
      
    • Header:

      Authorization: <BOT_SEND_TOKEN>
      
    • JSON/body fields:

      {
        "roomId": "={{ $json.body.roomId }}",
        "message": "Hello from n8n!",
        "replyToEventId": "={{ $json.body.eventId }}",
        "replyToSenderId": "={{ $json.body.senderId }}",
        "replyToBody": "={{ $json.body.originalContent }}"
      }
      

/send request body

/send accepts POST requests with a JSON object body. The Authorization header must be exactly the raw BOT_SEND_TOKEN value, without a Bearer prefix.

Required fields:

  • roomId — Matrix room ID to send into, for example !room:server.
  • message — reply text to send.

Optional fields:

  • replyToEventId — Matrix event ID to reply to. If set, the bot adds m.relates_to.m.in_reply_to.
  • replyToSenderId — sender MXID for the quoted fallback reply text, for example @user:server.
  • replyToBody — original message body to quote in the rich reply fallback.
  • asNotice — boolean. If true, sends msgtype: m.notice; otherwise sends m.text.

Minimal request:

{
  "roomId": "!room:server",
  "message": "Hello from n8n!"
}

Reply request using the inbound webhook payload:

{
  "roomId": "={{ $json.body.roomId }}",
  "message": "Hello from n8n!",
  "replyToEventId": "={{ $json.body.eventId }}",
  "replyToSenderId": "={{ $json.body.senderId }}",
  "replyToBody": "={{ $json.body.originalContent }}",
  "asNotice": false
}

Behavior notes:

  • Request body size is limited to 64 KiB.
  • Invalid JSON, missing roomId, or missing message returns 400.
  • Unauthorized requests return 401.
  • Successful sends return JSON like { "event_id": "$event:server" }.

The Webhook node exposes the bot payload under $json.body:

{
  "text": "cleaned mention text",
  "originalContent": "original Matrix body",
  "roomId": "!room:server",
  "eventId": "$event:server",
  "senderId": "@user:server",
  "timestamp": 1234567890,
  "formattedBody": null
}

Bot verification info

The bridge exposes a small authenticated helper endpoint for out-of-band device verification:

GET /verify-info
Authorization: <BOT_SEND_TOKEN>

Example:

curl -H "Authorization: $BOT_SEND_TOKEN" http://localhost:8080/verify-info

It returns the bot MXID, device ID, display name, and Matrix device keys. Compare the deviceId and ed25519Fingerprint over a trusted channel with what your Matrix client shows for the bot device, then mark the device as verified in your Matrix client.

When using Docker Compose, run the curl from inside the n8n/bot network or temporarily expose the bot port. The provided Compose file binds /send and /verify-info to 0.0.0.0 inside the container but does not publish the port to the host.

Development

cd bot
npm install
npm run build
npm test