SynapseCom
CS

Developer — OpenClaw Integration

A complete, step-by-step guide to connect a Synapse deployment to an OpenClaw AI agent. Includes shell scripts and agent prompts you can paste into OpenClaw to automate the setup.

1. Architecture overview

Synapse talks to OpenClaw over two HTTP round-trips. Outbound, Synapse POSTs each user message to the plugin's /webhook/synapse route. Inbound, the plugin POSTs the agent's reply back to /api/ai/inbound on Synapse, which relays it to the user over SignalR (AiReply event).

iOS app
   │
   ▼  POST /api/ai/message   { "message": "…" }           (Bearer JWT)
Synapse backend
   │
   ▼  POST {gateway}/webhook/synapse  { text, user_id, token }
OpenClaw gateway (plugin route)
   │
   ▼  agent.run(text) → reply
OpenClaw plugin outbound handler
   │
   ▼  POST {synapse}/api/ai/inbound   { user_id, text, token }   (inboundToken)
Synapse backend
   │
   ▼  SignalR AiReply → user:{userId} group
iOS app displays reply
            
  • Two tokens, two directions. Gateway Token authenticates Synapse → OpenClaw. Inbound Token authenticates OpenClaw → Synapse.
  • Per-user allowlist. Admins explicitly grant each member access. Users not on the allowlist get HTTP 403 and never see the chat tile in iOS.
  • Not E2E-encrypted. Unlike regular Synapse chats, messages to the agent flow as plaintext through your backend to your OpenClaw instance. Treat the agent like any SaaS integration that sees message content.

2. Prerequisites

  • A deployed Synapse backend with admin access (your instance of synapse-communicator).
  • A running OpenClaw gateway reachable over HTTPS with a valid Gateway Token (OPENCLAW_GATEWAY_TOKEN).
  • SSH (or equivalent) access to the OpenClaw server, or the ability to install plugins via your OpenClaw control plane.
  • The @synapse/openclaw-synapse-channel plugin source (shipped in the Synapse repo at openclaw-synapse-plugin/).
Network reachability. Your OpenClaw server must be able to reach your Synapse backend over HTTPS, and your Synapse backend must be able to reach the OpenClaw gateway. If either direction is blocked by firewall/NAT, replies will never arrive even though the outbound call succeeds.

3. Step 1 — Configure the gateway in Synapse Admin

  1. Sign in to the Synapse admin portal and navigate to Integrations → OpenClaw.
  2. Gateway URL — enter the base URL of your OpenClaw gateway (e.g. https://openclaw.example.com or http://openclaw:18789). Do not include the /webhook/synapse suffix — Synapse appends it automatically.
  3. Gateway Token — paste the token that matches your plugin's channels.synapse.token. If the plugin is not installed yet, write it down — you will use the same value in step 2.
  4. Click Test connection. You should see "Connected successfully" with a latency reading.
  5. Click Save.
  6. In the Plugin setup section that appears, click Generate next to Inbound Token. Copy the token immediately — it is shown exactly once.
  7. Copy the Synapse Inbound Webhook URL shown below the token. You will paste both values into the plugin config.
Why two tokens? Synapse proves itself to OpenClaw with the Gateway Token. OpenClaw proves itself to Synapse with the Inbound Token. Regenerating one does not affect the other; regenerate the inbound token whenever you want to revoke a plugin deployment.

4. Step 2 — Install the Synapse channel plugin on OpenClaw

The plugin registers the POST /webhook/synapse route on the gateway and wires the agent's outbound reply to Synapse's inbound endpoint.

2.1 — Copy the plugin onto the OpenClaw host

From your workstation:

cd <your-synapse-checkout>/openclaw-synapse-plugin
tar czf openclaw-synapse-plugin.tgz --exclude=node_modules --exclude=.git .
scp openclaw-synapse-plugin.tgz <user>@<openclaw-host>:/tmp/

2.2 — Extract and install dependencies

On the OpenClaw host:

ssh <user>@<openclaw-host>
sudo mkdir -p /opt/openclaw/plugins/synapse
sudo tar xzf /tmp/openclaw-synapse-plugin.tgz -C /opt/openclaw/plugins/synapse
cd /opt/openclaw/plugins/synapse
sudo npm install --omit=dev

If your OpenClaw distribution ships a plugin installer, prefer it:

openclaw plugins install /opt/openclaw/plugins/synapse

2.3 — Configure the channel

Edit openclaw.config.yaml on the gateway and add a synapse block under channels:. Use the exact values copied from Synapse Admin → Integrations.

channels:
  synapse:
    # The same value you saved as Gateway Token in Synapse Admin.
    token: "<OPENCLAW_GATEWAY_TOKEN>"

    # Paste the "Synapse Inbound Webhook URL" from the Plugin setup panel.
    incomingUrl: "https://<your-synapse>/api/ai/inbound"

    # Paste the Inbound Token you generated (shown only once).
    inboundToken: "<INBOUND_TOKEN>"

    # "open" = any Synapse user allowed by admin can DM the agent.
    # "allowlist" = also require the user's composite ID to be in allowedUserIds.
    dmPolicy: open
    # allowedUserIds:
    #   - "<companyId>:<userId>"

2.4 — Restart the gateway

The webhook route is registered at startup, so a restart is mandatory.

# Pick whichever matches your deployment:
sudo systemctl restart openclaw
# or
docker restart openclaw
# or
pm2 restart openclaw

2.5 — Verify from the server

curl -i -X POST http://localhost:18789/webhook/synapse \
     -H 'Content-Type: application/json' \
     -d '{"text":"ping","user_id":"00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000","token":"<OPENCLAW_GATEWAY_TOKEN>"}'

Expected: HTTP 200 or 202. If you get 404, the plugin did not load — recheck the install path and the server logs. If you get 401, the token does not match.

5. Step 3 — Grant users access

OpenClaw access is per-user. A user who is not on the allowlist cannot send messages and does not even see the "OpenClaw Agent" tile in their iOS conversation list.

  1. In Synapse Admin go to Users.
  2. Find the column titled OpenClaw. Each row has a toggle.
  3. Toggle ON for each member who should be able to chat with the agent. The change takes effect immediately.

The allowlist is stored in CompanySettings.OpenClawAllowedUserIds. It is a standard part of the per-company settings JSON and travels with your database backups.

6. Step 4 — Verify end-to-end

6.1 — From Synapse Admin

In Integrations → OpenClaw, click Send test message. You get back the gateway's raw status code, the response body, and an interpretation hint.

  • HTTP 200/202 — the plugin accepted the test payload. Proceed to iOS.
  • HTTP 404 — plugin not loaded. Recheck step 2.3 and restart.
  • HTTP 401 / 403 — Gateway Token mismatch between Admin and channels.synapse.token.
  • HTTP 400 — payload schema mismatch. Update the plugin to the version shipped with your Synapse release.

6.2 — From iOS

  1. Sign in as an allowlisted user. The OpenClaw Agent tile appears at the top of the conversation list.
  2. Tap it, type a message, send.
  3. The reply arrives asynchronously over SignalR — typically within the agent's normal response time.

7. Agent prompts — automate setup from inside OpenClaw

If your OpenClaw deployment runs an agent with shell / file-system tools, you can have it perform steps 2.1 – 2.5 on its own host. Paste the prompts below into the agent. Replace placeholders in angle brackets first.

Prompt A — Install the Synapse channel plugin

You are running on the OpenClaw host and have shell access.
Install the Synapse channel plugin so this gateway can receive and send messages through Synapse.

Inputs:
  SYNAPSE_GATEWAY_TOKEN   = <paste value from Synapse Admin → Integrations → Gateway Token>
  SYNAPSE_INBOUND_URL     = <paste value from Integrations → Plugin setup → Synapse Inbound Webhook URL>
  SYNAPSE_INBOUND_TOKEN   = <paste value from Integrations → Plugin setup → Inbound Token (shown once)>
  PLUGIN_TARBALL_URL      = <URL to openclaw-synapse-plugin.tgz, or /tmp path if already uploaded>
  OPENCLAW_CONFIG_PATH    = <absolute path to openclaw.config.yaml on this host>

Do the following, in order:
  1. Create /opt/openclaw/plugins/synapse if it does not exist.
  2. Download or copy the plugin tarball to that directory and extract it.
  3. Run `npm install --omit=dev` inside the plugin directory.
  4. Edit OPENCLAW_CONFIG_PATH and insert (or update) under `channels:`:
       synapse:
         token: "${SYNAPSE_GATEWAY_TOKEN}"
         incomingUrl: "${SYNAPSE_INBOUND_URL}"
         inboundToken: "${SYNAPSE_INBOUND_TOKEN}"
         dmPolicy: open
     Preserve any other channels that already exist. Never overwrite unrelated keys.
  5. Validate the YAML before saving. If the file is malformed, abort and report the error.
  6. Restart the OpenClaw service (try `systemctl restart openclaw`; if it fails, try
     `docker restart openclaw`; if neither exists, report how the service runs).
  7. Wait 5 seconds, then curl `http://localhost:18789/webhook/synapse` with a dummy ping body:
       {"text":"ping","user_id":"00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000","token":"${SYNAPSE_GATEWAY_TOKEN}"}
  8. Report the HTTP status + body. Any non-2xx is an installation failure — explain likely cause.

Never log any token value in plaintext to stdout or to any file other than the config itself.

Prompt B — Rotate the Inbound Token safely

You are on the OpenClaw host. Rotate the inboundToken used by the Synapse channel.

Preconditions: the admin has clicked "Regenerate" in Synapse Admin → Integrations and given you:
  NEW_INBOUND_TOKEN = <the freshly generated token, only shown once>

Steps:
  1. Read OPENCLAW_CONFIG_PATH and locate channels.synapse.inboundToken.
  2. Replace its value with NEW_INBOUND_TOKEN. Keep all other keys as-is.
  3. Save and reload OpenClaw (`systemctl reload openclaw` if supported, otherwise restart).
  4. Ask the admin to send a test message from Synapse Admin → "Send test message".
     Expect HTTP 200/202. If 401/403, roll back to the previous value and report.

Never echo NEW_INBOUND_TOKEN in logs.

Prompt C — Verify inbound connectivity from OpenClaw → Synapse

You are on the OpenClaw host. Confirm that this host can reach Synapse for replies.

Inputs:
  SYNAPSE_INBOUND_URL   = <https://<your-synapse>/api/ai/inbound>
  SYNAPSE_INBOUND_TOKEN = <as configured in channels.synapse.inboundToken>

Run:
  curl -sS -o /tmp/out -w '%{http_code}\n' -X POST "$SYNAPSE_INBOUND_URL" \
       -H 'Content-Type: application/json' \
       --data '{
         "user_id": "00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000",
         "text":    "[inbound-probe]",
         "token":   "'"$SYNAPSE_INBOUND_TOKEN"'"
       }'

Interpret:
  401 = inbound token is wrong — fix channels.synapse.inboundToken.
  404 = Synapse URL is wrong or backend does not expose /api/ai/inbound.
  Any 5xx = Synapse backend error — share the body from /tmp/out.
  200  = Synapse accepted the probe. Plugin-to-Synapse path is healthy.

Report the status code and a one-line diagnosis.

8. Scripts

8.1 — One-shot plugin installer

Save as install-synapse-plugin.sh on the OpenClaw host, fill in the three variables at the top, and run.

#!/usr/bin/env bash
set -euo pipefail

# ─── fill these in ─────────────────────────────────────────────
SYNAPSE_GATEWAY_TOKEN="${SYNAPSE_GATEWAY_TOKEN:?set me}"
SYNAPSE_INBOUND_URL="${SYNAPSE_INBOUND_URL:?set me}"
SYNAPSE_INBOUND_TOKEN="${SYNAPSE_INBOUND_TOKEN:?set me}"
PLUGIN_TARBALL="${PLUGIN_TARBALL:-/tmp/openclaw-synapse-plugin.tgz}"
OPENCLAW_CONFIG="${OPENCLAW_CONFIG:-/etc/openclaw/openclaw.config.yaml}"
PLUGIN_DIR="${PLUGIN_DIR:-/opt/openclaw/plugins/synapse}"
# ───────────────────────────────────────────────────────────────

echo "→ installing plugin into $PLUGIN_DIR"
sudo mkdir -p "$PLUGIN_DIR"
sudo tar xzf "$PLUGIN_TARBALL" -C "$PLUGIN_DIR"
(cd "$PLUGIN_DIR" && sudo npm install --omit=dev)

echo "→ patching $OPENCLAW_CONFIG"
if ! command -v yq >/dev/null; then
  echo "yq is required (https://github.com/mikefarah/yq). Aborting." >&2
  exit 1
fi
sudo cp "$OPENCLAW_CONFIG" "$OPENCLAW_CONFIG.bak.$(date +%s)"
sudo yq -i "
  .channels.synapse.token        = strenv(SYNAPSE_GATEWAY_TOKEN) |
  .channels.synapse.incomingUrl  = strenv(SYNAPSE_INBOUND_URL)   |
  .channels.synapse.inboundToken = strenv(SYNAPSE_INBOUND_TOKEN) |
  .channels.synapse.dmPolicy     = \"open\"
" "$OPENCLAW_CONFIG"

echo "→ restarting OpenClaw"
if systemctl list-units --type=service | grep -q '^openclaw'; then
  sudo systemctl restart openclaw
elif docker ps --format '{{.Names}}' | grep -q '^openclaw$'; then
  docker restart openclaw
else
  echo "Unknown service manager — restart OpenClaw manually." >&2
  exit 1
fi

echo "→ smoke test"
sleep 5
curl -sS -o /tmp/synapse-plugin-probe -w 'HTTP %{http_code}\n' -X POST \
  http://localhost:18789/webhook/synapse \
  -H 'Content-Type: application/json' \
  --data "{\"text\":\"[probe]\",\"user_id\":\"00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000\",\"token\":\"$SYNAPSE_GATEWAY_TOKEN\"}"
echo "Response body:"
cat /tmp/synapse-plugin-probe
echo

8.2 — Check current plugin health

#!/usr/bin/env bash
set -euo pipefail

GATEWAY="${GATEWAY:-http://localhost:18789}"
TOKEN="${SYNAPSE_GATEWAY_TOKEN:?set me}"

status=$(curl -sS -o /tmp/out -w '%{http_code}' -X POST \
  "$GATEWAY/webhook/synapse" \
  -H 'Content-Type: application/json' \
  --data "{\"text\":\"[healthcheck]\",\"user_id\":\"00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000\",\"token\":\"$TOKEN\"}")

case "$status" in
  200|202) echo "OK — $status"; exit 0 ;;
  401|403) echo "AUTH FAIL — token mismatch"; exit 2 ;;
  404)     echo "PLUGIN MISSING — route not registered"; exit 3 ;;
  *)       echo "UNEXPECTED — HTTP $status"; cat /tmp/out; exit 4 ;;
esac

9. API reference

User endpoints (require JWT)

Method Path Purpose
GET/api/ai/statusReturns { allowed: boolean }. iOS hides the agent tile when false.
POST/api/ai/messageBody { message: string }. Returns 202 {queued:true}. Reply arrives via SignalR AiReply.

Admin endpoints (require CompanyAdmin policy)

Method Path Purpose
GET/api/admin/integrations/openclawCurrent gateway URL, token hints, inbound webhook URL.
PUT/api/admin/integrations/openclawSave Gateway URL + Token. Leave token blank to keep the existing one.
DELETE/api/admin/integrations/openclawRemove the entire OpenClaw configuration.
POST/api/admin/integrations/openclaw/testTests Gateway URL + Token against /v1/models.
POST/api/admin/integrations/openclaw/pingFull round-trip: sends a probe to /webhook/synapse and returns gateway status + body.
POST/api/admin/integrations/openclaw/inbound-tokenGenerates a fresh Inbound Token (returned once).
GET/api/admin/integrations/openclaw/allowed-usersLists allowlisted user IDs.
PUT/api/admin/integrations/openclaw/allowed-users/{userId}Body { allowed: boolean }. Toggles a single user.

OpenClaw → Synapse inbound webhook

Method Path Body
POST/api/ai/inbound{ user_id: "<companyId>:<userId>", text, token }

10. Troubleshooting

iOS: "OpenClaw gateway is reachable, but the Synapse channel plugin isn't installed on it (got 404)"

Plugin route /webhook/synapse is not registered. Recheck step 2.3 — is the plugin block in openclaw.config.yaml? Did you restart the gateway after editing?

iOS: "OpenClaw rejected Synapse's gateway token"

The value in Admin → Integrations → Gateway Token does not match channels.synapse.token in openclaw.config.yaml. Watch out for env-var substitution: if the plugin expands ${OPENCLAW_GATEWAY_TOKEN} but the variable is empty in the service environment, the plugin sees an empty token and rejects everything.

iOS: "Your admin has not granted you access to the OpenClaw agent"

The user is not on the allowlist. Admin → Users → toggle OpenClaw on for this user.

iOS: "OpenClaw timed out"

Synapse waited 30 s for the gateway. Agent took longer or is stuck. Check OpenClaw logs. If a specific user triggers this reliably, narrow down the prompt or raise the plugin's internal timeout.

No reply arrives but Synapse returned 202

OpenClaw accepted the message but never POSTed a reply back. Usual causes: the plugin cannot reach incomingUrl (firewall or TLS handshake failure), the inboundToken is wrong (Synapse logs a 401 on /api/ai/inbound), or the agent is crashing mid-run. Run Prompt C from section 7.

11. Security notes

  • Not E2E-encrypted. Messages to the agent are plaintext at both the Synapse backend and OpenClaw. Treat them like any other third-party integration and inform your users accordingly.
  • Per-user allowlist is mandatory. Even after configuring the gateway, no user can talk to the agent until explicitly enabled. This keeps accidental data exposure contained.
  • Rotate the Inbound Token when a plugin deployment is decommissioned or when a shared environment changes hands. The old token is invalidated immediately on regeneration.
  • Keep gateway traffic TLS-terminated end-to-end. Even inside a VPC, prefer HTTPS between Synapse and the gateway so tokens are never observable by packet captures.

Need help integrating Synapse with a different agent platform?

Get in Touch