Synology Chat Integration with OpenClaw via Webhooks

Configure Synology Chat to work with OpenClaw using two webhooks for direct messages. This guide covers setup steps for administrators and plugin installation.

Read this when

  • Setting up Synology Chat with OpenClaw
  • Debugging Synology Chat webhook routing

Synology Chat links up with OpenClaw using two webhooks. An outgoing webhook on the Synology Chat side forwards inbound direct messages to the Gateway, while an incoming webhook on Synology Chat handles the replies sent back.

This is an official plugin that gets installed separately. It handles direct messages only, and both plain text and hosted file uploads are supported.

Install

openclaw plugins install @openclaw/synology-chat

When running from a local git checkout:

openclaw plugins install ./path/to/local/synology-chat-plugin

Further reading: Plugins

Quick setup

  1. Install the plugin as described above.
  2. Within the Synology Chat integrations panel:
    • Set up an incoming webhook and note its URL.
    • Set up an outgoing webhook, supplying your secret token.
  3. Configure the outgoing webhook URL to target your OpenClaw Gateway:
    • https://gateway-host/webhook/synology is the default.
    • Or use a custom channels.synology-chat.webhookPath.
    • Save that exact publicly reachable HTTPS URL as channels.synology-chat.webhookUrl so the NAS can pull hosted attachments.
  4. Wrap up the configuration in OpenClaw. Synology Chat shows up in the same channel setup list for both workflows:
    • Guided: openclaw onboard or openclaw channels add
    • Direct: openclaw channels add --channel synology-chat --token <token> --url <incoming-webhook-url> --webhook-url <public-outgoing-webhook-url>
  5. Restart the Gateway, then send a direct message to the Synology Chat bot.

Authentication details for webhooks:

  • OpenClaw reads the outgoing webhook token from body.token, then ?token=..., and finally headers.
  • Header formats that are accepted:
    • x-synology-token
    • x-webhook-token
    • x-openclaw-token
    • Authorization: Bearer <token>
  • Requests with missing or empty tokens are rejected.
  • Payloads can arrive as application/x-www-form-urlencoded or application/json; token, user_id, and text must all be present.

Inbound durability

Once the token, sender policy, and rate limit checks all pass, OpenClaw strips the webhook token from the stored envelope and durably queues the event prior to sending an acknowledgement. The route only returns 204 after that append completes; if persistence fails, 503 is returned so Synology Chat can retry rather than drop the message silently. The durable 204 includes x-openclaw-delivery-accepted: durable; responses tied to authentication, validation, or storage errors omit the marker, which lets reverse proxies require it to tell durable acceptance apart from a generic reply.

Events that are pending or retryable survive a Gateway restart. Synology's stable post_id prevents duplicate queue entries as long as a matching active or retained completion record exists. Delivery is at least once across the queue-to-agent handoff, so a crash at that boundary can still replay a turn.

A minimal configuration looks like this:

{
  channels: {
    "synology-chat": {
      enabled: true,
      token: "synology-outgoing-token",
      incomingUrl: "https://nas.example.com/webapi/entry.cgi?api=SYNO.Chat.External&method=incoming&version=2&token=...",
      webhookUrl: "https://gateway.example.com/webhook/synology",
      webhookPath: "/webhook/synology",
      dmPolicy: "allowlist",
      allowedUserIds: ["123456"],
      rateLimitPerMinute: 30,
      allowInsecureSsl: false,
    },
  },
}

Environment variables

For the default account, environment variables work:

  • SYNOLOGY_CHAT_TOKEN
  • SYNOLOGY_CHAT_INCOMING_URL
  • SYNOLOGY_NAS_HOST
  • SYNOLOGY_ALLOWED_USER_IDS (comma-separated)
  • SYNOLOGY_RATE_LIMIT
  • OPENCLAW_BOT_NAME

Environment variables take a back seat to config values.

SYNOLOGY_CHAT_INCOMING_URL and SYNOLOGY_NAS_HOST are not settable from a workspace .env; refer to Workspace .env files.

DM policy and access control

  • Valid dmPolicy options: allowlist (the default), open, and disabled. Synology Chat has no pairing flow, so senders must be approved by adding their numeric Synology user IDs to allowedUserIds.
  • allowedUserIds takes a list (or a comma-separated string) of Synology user IDs.
  • Under allowlist mode, an empty allowedUserIds list counts as misconfiguration, and the webhook route refuses to start.
  • dmPolicy: "open" permits public DMs only when allowedUserIds contains "*"; with restrictive entries, only matching users can converse. open with an empty allowedUserIds list likewise blocks route startup.
  • dmPolicy: "disabled" disables DMs.
  • Reply recipient binding sticks with stable numeric user_id by default. channels.synology-chat.dangerouslyAllowNameMatching: true serves as break-glass compatibility mode, bringing back mutable username or nickname lookup for reply delivery.

Outbound delivery

Use numeric Synology Chat user IDs as the destination for messages. The prefixes synology-chat:, synology_chat:, and synology: are all valid.

Examples:

openclaw message send --channel synology-chat --target 123456 --message "Hello from OpenClaw"
openclaw message send --channel synology-chat --target synology-chat:123456 --message "Hello again"
openclaw message send --channel synology-chat --target synology:123456 --message "Short prefix"

Outbound messages get split into 2000-character chunks, and standard links stay as they are. In the Synology Chat Admin Console, on a supported Chat Server release, leave Hide URL previews in conversations and channels turned on.

When handling attachments, OpenClaw fetches the source under its guarded outbound-media policy, stores the resulting bytes in bounded plugin-scoped SQLite state, and hands Synology a short-lived opaque HTTPS capability on the configured webhook route. The NAS only ever sees this OpenClaw-hosted URL; the original remote or local media reference is never passed along. Capabilities are scoped to a specific account and route, can be reused for delayed GET or HEAD requests within their ten-minute window, and expire on their own. Attachment files are capped at 32 MB. Each account can handle at most four attachment responses at once and 128 MB per minute; responses that stall get closed after two minutes. Byte-range responses are not offered.

webhookUrl and webhookPath serve distinct purposes:

  • webhookUrl is the precise externally reachable HTTPS callback that Synology Chat is configured with. When OpenClaw builds attachment capabilities, it uses the public origin, path, and any existing query string from this value.
  • webhookPath is the internal Gateway route. A reverse proxy can map the public URL to this route, but it should expose only this plugin path, not the broader Gateway HTTP surface.
  • incomingUrl works in the reverse direction: OpenClaw relies on it to send replies back to the NAS.

OpenClaw never derives the public URL from the Host or X-Forwarded-* headers, and it never falls back to forwarding the original source URL. If webhookUrl is absent or invalid, inbound messages and outbound text keep functioning, but attachment sends fail with a clear setup error.

Multi-account

Multiple Synology Chat accounts are supported under channels.synology-chat.accounts. Each account can override the token, incoming URL, public webhook URL, webhook path, DM policy, and limits. Direct-message sessions are isolated per account and user, so the same numeric user_id on two different Synology accounts does not share transcript state. Give every enabled account its own distinct webhookPath. OpenClaw rejects duplicate exact paths and refuses to start named accounts that only inherit a shared webhook path in multi-account setups. If you deliberately need legacy inheritance for a named account, set dangerouslyAllowInheritedWebhookPath: true on that account or at channels.synology-chat, but duplicate exact paths are still rejected fail-closed. Prefer explicit per-account paths.

{
  channels: {
    "synology-chat": {
      enabled: true,
      accounts: {
        default: {
          token: "token-a",
          incomingUrl: "https://nas-a.example.com/...token=...",
          webhookUrl: "https://gateway.example.com/webhook/synology",
        },
        alerts: {
          token: "token-b",
          incomingUrl: "https://nas-b.example.com/...token=...",
          webhookUrl: "https://gateway.example.com/webhook/synology-alerts",
          webhookPath: "/webhook/synology-alerts",
          dmPolicy: "allowlist",
          allowedUserIds: ["987654"],
        },
      },
    },
  },
}

Security notes

  • Treat token as confidential and rotate it if it leaks.
  • Keep allowInsecureSsl: false unless you explicitly trust a self-signed local NAS cert.
  • Inbound webhook requests are token-verified and rate-limited per sender (rateLimitPerMinute, default 30).
  • Invalid token checks use constant-time secret comparison and fail closed; repeated invalid-token attempts temporarily lock out the source IP.
  • Inbound message text is sanitized against known prompt-injection patterns and truncated at 4000 characters.
  • Prefer dmPolicy: "allowlist" for production.
  • Keep dangerouslyAllowNameMatching off unless you explicitly need legacy username-based reply delivery.
  • Keep dangerouslyAllowInheritedWebhookPath off unless you explicitly accept shared-path routing risk in a multi-account setup.
  • Reverse-proxy access logs can capture attachment capability tokens. Disable query-string logging or redact __openclaw_synology_media_token_* parameters, and keep application logs free of full capability URLs.
  • Hosted attachments use Content-Disposition: attachment, X-Content-Type-Options: nosniff, and Cache-Control: no-store. Files declared or named as HTML, SVG, or XML are rejected. Frozen bytes that begin as a UTF-8, UTF-16, or UTF-32 markup document after an optional encoding marker, whitespace, and comments are also rejected; literal tags later in passive text or source files do not make those files active documents.

Troubleshooting

  • Missing required fields (token, user_id, text):
    • the outgoing webhook payload is missing one of the required fields
    • if Synology sends the token in headers, make sure the gateway/proxy preserves those headers
  • Invalid token:
    • the outgoing webhook secret does not match channels.synology-chat.token
    • the request is hitting the wrong account/webhook path
    • a reverse proxy stripped the token header before the request reached OpenClaw
  • Rate limit exceeded:
    • too many invalid token attempts from the same source can temporarily lock that source out
    • authenticated senders also have a separate per-user message rate limit
  • Allowlist is empty. Configure allowedUserIds or use dmPolicy=open with allowedUserIds=["*"].:
    • dmPolicy="allowlist" is enabled but no users are configured
  • User not authorized:
    • the sender's numeric user_id is not in allowedUserIds
  • Synology Chat attachments require webhookUrl:
    • set the account's exact externally reachable HTTPS outgoing-webhook callback URL
    • confirm the reverse proxy maps only that public route to webhookPath
    • text and inbound messaging remain available while attachment setup is incomplete
1,514 words · updated Aug 16, 2026