Synology Chat connects to Apus through a webhook pair: a Synology Chat outgoing webhook posts inbound direct messages to the Gateway, and replies go back through a Synology Chat incoming webhook.

Status: official plugin, installed separately. Direct messages only; text and hosted file sends are supported.

Install

apus plugins install @openclaw/synology-chat

Local checkout (when running from a git repo):

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

Details: Plugins

Quick setup

  1. Install the plugin (above).
  2. In Synology Chat integrations:
    • Create an incoming webhook and copy its URL.
    • Create an outgoing webhook with your secret token.
  3. Point the outgoing webhook URL to your Apus Gateway:
    • https://gateway-host/webhook/synology by default.
    • Or your custom channels.synology-chat.webhookPath.
    • Record that exact externally reachable HTTPS URL as channels.synology-chat.webhookUrl so the NAS can retrieve hosted attachments.
  4. Finish setup in Apus. Synology Chat appears in the same channel setup list in both flows:
    • Guided: apus onboard or apus channels add
    • Direct: apus channels add --channel synology-chat --token <token> --url <incoming-webhook-url> --webhook-url <public-outgoing-webhook-url>
  5. Check apus channels status --probe, then send a DM to the Synology Chat bot. Start the Gateway if it is offline; config changes follow hot reload.

Webhook auth details:

Inbound durability

After token, sender-policy, and rate-limit checks pass, Apus removes the webhook token from the stored envelope and durably queues the event before acknowledging it. The route returns 204 only after that append succeeds; a persistence failure returns 503 so Synology Chat can retry instead of silently losing the message. The durable 204 carries x-apus-delivery-accepted: durable; authentication, validation, and storage-error responses omit the marker, so reverse proxies can require it to distinguish durable acceptance from a generic response.

Pending or retryable events survive a Gateway restart. Synology's stable post_id suppresses duplicate queue entries while the corresponding active or retained completion record exists. Delivery remains at least once across the queue-to-agent handoff, so a crash at that boundary can still replay a turn.

Minimal config:

{
  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, you can use env vars:

Config values override env vars.

SYNOLOGY_CHAT_INCOMING_URL and SYNOLOGY_NAS_HOST cannot be set from a workspace .env; see Workspace .env files.

DM policy and access control

Outbound delivery

Use numeric Synology Chat user IDs as targets. The synology-chat:, synology_chat:, and synology: prefixes are accepted.

Examples:

apus message send --channel synology-chat --target 123456 --message "Hello from Apus"
apus message send --channel synology-chat --target synology-chat:123456 --message "Hello again"
apus message send --channel synology-chat --target synology:123456 --message "Short prefix"

Outbound text is chunked at 2000 characters, and ordinary links remain intact. Keep Hide URL previews in conversations and channels enabled in Synology Chat Admin Console on a supported Chat Server release.

For attachments, Apus loads the source under its guarded outbound-media policy, freezes the resulting bytes in bounded plugin-scoped SQLite state, and gives Synology a short-lived opaque HTTPS capability on the configured webhook route. The NAS receives only this Apus-hosted URL, never the original remote or local media reference. Capabilities are account- and route-scoped, reusable for delayed GET or HEAD requests during their ten-minute lifetime, and expire automatically. Files are limited to 32 MB. Each account can serve at most four attachment responses concurrently and 128 MB per minute; stalled responses are closed after two minutes. Byte-range responses are not advertised.

webhookUrl and webhookPath have different roles:

Apus never derives the public URL from Host or X-Forwarded-* headers and never falls back to forwarding the original source URL. If webhookUrl is missing or invalid, inbound messages and outbound text continue to work, while attachment sends fail with an actionable setup error.

Multi-account

Multiple Synology Chat accounts are supported under channels.synology-chat.accounts. Each account can override 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 each enabled account a distinct webhookPath. Apus rejects duplicate exact paths and refuses to start named accounts that only inherit a shared webhook path in multi-account setups. If you intentionally 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

Troubleshooting

Related