Set up Mattermost & Nextcloud Talk
Set up self-hosted team-chat channels: a Mattermost bot and a webhook-based Nextcloud Talk bot.
This guide connects Revka to two self-hosted team-chat platforms: Mattermost and Nextcloud Talk. Both keep your agent’s conversation history inside infrastructure you control, which makes them a good fit for private, regulated, or air-gapped deployments. Use this page when you want a Revka bot to read and reply in a Mattermost channel or a Nextcloud Talk room.
The two integrations work differently:
- Mattermost polls the Mattermost REST API v4 with a bot access token. It needs no public inbound port — Revka pulls new posts on a schedule.
- Nextcloud Talk runs in webhook mode. Nextcloud pushes events to your gateway at
POST /nextcloud-talk, so the gateway must be reachable over public HTTPS.
For the broader picture of how channels work, see Channels overview and the workspace-chat reference in Matrix, Mattermost & Nextcloud Talk. For the encrypted-room option, see Set up Telegram & Matrix.
Both channels are configured under [channels_config] in ~/.revka/config.toml. You can edit the file directly, or run revka onboard --channels-only to set them interactively. Apply changes by restarting the daemon.
Mattermost
Section titled “Mattermost”Mattermost is the simpler of the two: create a bot account, grab the channel ID, drop both into config, and run the daemon.
Create the bot account
Section titled “Create the bot account”- In Mattermost, open Main Menu → Integrations → Bot Accounts.
- Click Add Bot Account.
- Set a username, for example
revka-bot. - Grant the bot post and channel-read permissions (for example
post:allandchannel:read, or the equivalent scopes for your server). - Save the generated Access Token — this is the
bot_tokenvalue. It is shown once.
Find the channel ID
Section titled “Find the channel ID”- Open the channel you want the bot to monitor.
- Click the channel name in the header and choose View Info.
- Copy the ID value (for example
7j8k9l...). This is thechannel_id.
The channel_id is required for listen mode. Omit it to listen on every channel the bot account can access.
Configure Mattermost
Section titled “Configure Mattermost”Add this section to ~/.revka/config.toml:
[channels_config.mattermost]url = "https://mm.your-domain.com"bot_token = "your-bot-access-token"channel_id = "your-channel-id"allowed_users = ["*"]thread_replies = truemention_only = false| Field | Type | Default | Meaning |
|---|---|---|---|
url | string | — | Base URL of your Mattermost server. Required. |
bot_token | string | — | The bot account’s personal access token. Required. |
channel_id | string | — | Channel to listen to. Required for listen mode; omit to listen on all accessible channels. |
allowed_users | array | — | Mattermost user IDs allowed to interact. [] denies all; ["*"] allows everyone. |
thread_replies | bool | true | Reply to top-level messages in a thread on that post. |
mention_only | bool | false | When true, only process messages that @-mention the bot. |
proxy_url | string | — | Optional per-channel HTTP/SOCKS5 proxy. |
Mattermost also transcribes audio attachments when the shared [transcription] section is configured (25 MB audio limit). See Voice, TTS & transcription.
Threading and mention-only behavior
Section titled “Threading and mention-only behavior”- If a user replies inside an existing thread, Revka always replies in that same thread.
- With
thread_replies = true(the default), Revka answers a top-level message by threading on it. Withthread_replies = false, it answers at the channel root. - With
mention_only = true, Revka applies an extra filter after theallowed_userscheck: messages without an explicit@bot_usernamemention are ignored, and the mention token is stripped before the text reaches the model. This is useful in busy shared channels to cut unnecessary model calls.
Run it
Section titled “Run it”Start the full runtime so the channel supervisor begins polling:
revka daemonSend a message in the target channel and confirm the bot replies. For a first test, set allowed_users = ["*"], then tighten it to explicit user IDs once you have confirmed delivery.
Nextcloud Talk
Section titled “Nextcloud Talk”Nextcloud Talk uses a webhook bot: Nextcloud posts each room event to your gateway, Revka verifies the signature, runs the agent, and replies through the Nextcloud Talk OCS API. Because Nextcloud must reach your gateway, you need a public HTTPS URL.
Configure Nextcloud Talk
Section titled “Configure Nextcloud Talk”Add this section to ~/.revka/config.toml:
[channels_config.nextcloud_talk]base_url = "https://cloud.example.com"app_token = "nextcloud-talk-app-token"bot_name = "revka"webhook_secret = "your-webhook-secret"allowed_users = ["*"]| Field | Type | Default | Meaning |
|---|---|---|---|
base_url | string | — | Your Nextcloud instance URL. Required. Trailing slash is stripped. |
app_token | string | — | Bot app token, sent as Authorization: Bearer <token> on outbound OCS replies. Required. |
bot_name | string | revka | The bot’s Talk display name. Used for self-echo prevention (see below). |
webhook_secret | string | — | Shared HMAC secret for verifying inbound webhook signatures. Recommended. |
allowed_users | array | — | Allowed Nextcloud actor IDs. [] denies all; ["*"] allows everyone. |
proxy_url | string | — | Optional per-channel HTTP/SOCKS5 proxy. |
Expose the gateway and register the webhook
Section titled “Expose the gateway and register the webhook”Run the gateway or daemon, then point your Nextcloud Talk bot’s webhook URL at the gateway’s ingress path:
revka daemonhttps://<your-public-url>/nextcloud-talkThe gateway logs the registered route on startup (POST /nextcloud-talk — Nextcloud Talk bot webhook). Since Talk pushes events to you, the gateway must be reachable over public HTTPS — see Expose your gateway with a tunnel for a tunnel setup, and Network deployment, Raspberry Pi & proxy for which channels need a public port.
Webhook ingress endpoint
Section titled “Webhook ingress endpoint”The inbound webhook is part of the gateway’s public ingress surface (no bearer token — it is authenticated by signature instead).
POST /nextcloud-talkContent-Type: application/jsonX-Nextcloud-Talk-Random: <random-seed>X-Nextcloud-Talk-Signature: <hmac-hex>| Response | When |
|---|---|
404 | [channels_config.nextcloud_talk] is not configured. |
401 | Signature verification failed (only checked when a secret is set). |
200 | Accepted. Also returned when the payload contains no actionable user message (bot/system/non-allowed events are acknowledged silently). |
Outbound replies go to the Talk room from the webhook payload via the OCS chat API:
POST <base_url>/ocs/v2.php/apps/spreed/api/v1/chat/<room-token>?format=jsonAuthorization: Bearer <app_token>OCS-APIRequest: trueRevka handles both the Activity Streams 2.0 Create payload that current Nextcloud Talk bots send and the legacy message format, and it normalizes both millisecond and second timestamps.
Webhook signature verification
Section titled “Webhook signature verification”When webhook_secret is set, every inbound request is authenticated by an HMAC-SHA256 signature. Revka reads two headers and computes:
hex( hmac_sha256( secret, X-Nextcloud-Talk-Random + raw_request_body ) )The result is compared in constant time against the X-Nextcloud-Talk-Signature header. A leading sha256= prefix on the signature is accepted and stripped. The match is over the raw request body plus the random seed — not a re-serialized JSON object — so do not modify the body in any proxy between Nextcloud and the gateway. If the random header is missing, the signature is malformed, or the digest does not match, the gateway rejects the request with 401.
REVKA_NEXTCLOUD_TALK_WEBHOOK_SECRET
Section titled “REVKA_NEXTCLOUD_TALK_WEBHOOK_SECRET”The webhook secret can come from config or the environment. The environment variable takes priority:
export REVKA_NEXTCLOUD_TALK_WEBHOOK_SECRET="your-webhook-secret"Resolution order:
REVKA_NEXTCLOUD_TALK_WEBHOOK_SECRET(environment) — used when set and non-empty.webhook_secretunder[channels_config.nextcloud_talk]— used otherwise.
Use the environment variable when you would rather keep the secret out of config.toml. The same secret must be configured on the Nextcloud Talk bot so both sides compute the same HMAC.
bot_name self-echo prevention
Section titled “bot_name self-echo prevention”A webhook bot can see its own replies echoed back as new room events. Left unchecked, that creates a feedback loop where the agent answers itself forever. Revka drops self-originated events before they ever reach the model:
- Events whose actor type is
botsorapplicationare ignored. - Events whose actor ID carries the
bots/prefix are ignored. - Events whose actor name matches the configured
bot_name(compared case-insensitively) are ignored. The literal namerevkais always treated as the bot, even if you set a differentbot_name.
The name check is the safety net: Nextcloud does not always set the actor type reliably for bot-sent messages, so matching on bot_name catches echoes that slip through the type check. Set bot_name to the exact display name your bot uses in Talk so this filter works.
After the self-echo and event-type filters, the allowed_users allowlist applies: only messages from listed actor IDs are processed (["*"] allows all). Actor IDs are matched after stripping any users/ or bots/ prefix.
Validate
Section titled “Validate”- Set
allowed_users = ["*"]for the first run. - Send a test message in the target Talk room.
- Confirm Revka receives the event and replies in the same room.
- Tighten
allowed_usersto explicit actor IDs.
Troubleshooting
Section titled “Troubleshooting”- Mattermost: no reply. Check that
bot_tokenis the bot account’s access token, thaturlhas no typo, and that the sender’s user ID is inallowed_users. Withmention_only = true, only@-mentions are processed. - Nextcloud Talk:
404 Nextcloud Talk not configured. The[channels_config.nextcloud_talk]section is missing or the daemon was not restarted after editing config. - Nextcloud Talk:
401. The signature did not verify. Confirm the same secret is set on both sides, that theX-Nextcloud-Talk-Randomheader is forwarded, and that nothing rewrites the raw request body in transit. - Nextcloud Talk: webhook returns
200but no reply. The event was filtered — a bot/system event, a non-Noteobject, an unparseable message, or a sender not inallowed_users. The bot’s own messages are dropped by the self-echo filter. - Nextcloud Talk: the bot answers itself. Set
bot_nameto the bot’s exact Talk display name so the self-echo filter recognizes its own messages.
Run revka doctor or the dashboard Doctor page for structured diagnostics, and revka channel doctor to check channel wiring.
Related pages
Section titled “Related pages”- Connect a messaging channel — the general channel setup flow and allowlist semantics.
- Matrix, Mattermost & Nextcloud Talk — reference detail for the workspace-chat channels.
- Webhook ingress — all gateway webhook endpoints and request signing.
- Expose your gateway with a tunnel — give the Nextcloud Talk webhook a public HTTPS URL.
- revka channel & integrations — the
revka channelCLI commands.