Webhook Architecture

Authoritative overview of all inbound webhook handlers in OpenClaw. 9 providers route events through Cloudflare Tunnel (webhook.reri.co) or Tailscale-only paths to handler processes on the Hetzner VPS. Each handler validates signatures, deduplicates via processed_webhook_events, and logs to webhook_audit_log. The canonical endpoint registry is [[workspace/FUNNEL-REGISTRY]]. Read this hub when diagnosing missed webhooks, adding a new provider, or auditing security posture. Owner: Henry Hill / Claude Opus 4.7.

⚠️ P0 SECURITY FLAG: security-audit-funnel.timer STALE Last fired: 2026-04-27 13:00 UTC (6 days ago as of 2026-05-03). The timer fires Mondays 06:00 America/Los_Angeles — it missed Monday 2026-04-28 and will next fire Monday 2026-05-04. Per FUNNEL-REGISTRY governance and CLAUDE.md §Webhook Endpoint Governance: stale audit = security debt. Action: run node workspace/scripts/security-audit-funnel.js --dry-run manually NOW before this hub is published. Also: DocuSign WAF IP allowlist 90-day rotation check is overdue (last audit 2026-04-27). See cloudflare WAF section.

Quick reference

FieldValue
Live state probess -tlnp | grep -E ':1879[0-9]|:1880[0-9]' | wc -l
Documented count9 handler ports per CLAUDE.md Webhook Service Port Map
Live count<run probe and insert; expected ~6 active>
Drift(live - documented) percentage
Canonical endpoint registry[[workspace/FUNNEL-REGISTRY]]
Tunnel providerCloudflare Tunnel reri-api (ID: 849121e5-0db6-4076-b591-268783143377)
Public hostnamewebhook.reri.co (CNAME → 849121e5...cfargotunnel.com, proxied)
FallbackTailscale Funnel srv1347501.tailb025a7.ts.net (unadvertised, rollback path)
Documented handlers9
Live handler ports6 confirmed active (probed: 2026-05-03)
Dedup tableprocessed_webhook_events (Supabase CCP, 24h TTL)
Audit tablewebhook_audit_log (non-blocking write + /tmp/webhook-audit-fallback.jsonl)
Security audit scriptnode workspace/scripts/security-audit-funnel.js --dry-run
Security audit timersecurity-audit-funnel.timer (Mondays 06:00 PT)
Last audit timer fire2026-04-27 ⚠️ STALE
Last audit2026-05-03
Governance gateCLAUDE.md §Webhook Endpoint Governance
Owner agentsystem / aurora (inbound routing)

Components

  • [[workspace/FUNNEL-REGISTRY]] — canonical approved endpoint list (source of truth for governance)
  • [[workspace/webhooks/hubspot-handler.js]] — HubSpot + DocuSign + Make webhook handler (port 18790)
  • [[workspace/webhooks/quo-handler-enhanced.js]] — OpenPhone/Quo webhook handler (port 18792)
  • [[workspace/webhooks/salesmessage-handler-v4-complete.js]] — SalesMsg webhook handler (port 18793)
  • [[workspace/webhooks/twilio-voice-handler.js]] — Twilio voice + SMS handler (port 18797)
  • [[workspace/webhooks/gmail-push-handler.js]] — Gmail Push handler (port 18801, harden-pending)
  • [[workspace/webhooks/imessage-handler.js]] — BlueBubbles iMessage handler (port 18802, Tailscale-only)
  • [[workspace/scripts/security-audit-funnel.js]] — security posture audit script
  • [[workspace/scripts/webhook-dedup.js]] — deduplication utility (processed_webhook_events)
  • [[workspace/scripts/webhook-audit.js]] — non-blocking audit log writer

Inbound webhook handlers

Handler 1 — HubSpot + DocuSign + Make (port 18790)

FieldValue
Port18790
Handler[[workspace/webhooks/hubspot-handler.js]]
Process managerPM2 (hubspot, id:3)
Tunnel path(s)/webhook/hubspot, /hubspot, /webhook/hubspot/actions/*, /webhook/hubspot/api/dispo
Tunnel path — DocuSign/webhook/docusign
Tunnel path — Make/webhook/make
Sig verify — HubSpot✅ v1 HMAC-SHA256(body)
Sig verify — DocuSign✅ WAF IP allowlist (Cloudflare Pro custom rule, 90-day rotation)
Sig verify — Make⚠️ token/query param only
IP filterWAF header filter (Cloudflare Pro)
Dedup✅ processed_webhook_events 24h TTL
Audit log✅ webhook_audit_log
Statusproduction
OAuth callback/oauth/callback on Tailscale Funnel (HubSpot OAuth, one-time install path)

Cross-links: hubspot · cloudflare · openclaw-fragmentation-fix-2026-05-01

Handler 2 — OpenPhone / Quo (port 18792)

FieldValue
Port18792
Handler[[workspace/webhooks/quo-handler-enhanced.js]]
Process managersystemd openphone-webhook.service
Tunnel path(s)/webhook/openphone, /webhook/quo
Sig verify✅ HMAC(secret, timestamp.body)
IP filterN/A (no published OpenPhone IP ranges)
Dedup✅ processed_webhook_events 24h TTL
Audit log✅ webhook_audit_log
Statusproduction
10DLC flag⚠️ A2P 10DLC repeat-denial active — TCPA risk uncapped. See osil-twilio-10dlc-resubmission-2026-05-03

Cross-links: openphone-quo · twilio

Handler 3 — SalesMsg (port 18793)

FieldValue
Port18793
Handler[[workspace/webhooks/salesmessage-handler-v4-complete.js]]
Process managerPM2 (salesmsg, id:2)
Tunnel path(s)/webhook/salesmessage, /webhooks/salesmessage
Sig verify✅ query token ?secret=<token> (constant-time comparison)
NoteSalesMsg uses query-param token, NOT HMAC. KB once said otherwise — KB was wrong. Per CLAUDE.md §Webhook Endpoint Governance rule 6. Never switch to HMAC without live header verification.
IP filterN/A
Dedup✅ processed_webhook_events 24h TTL
Audit log✅ webhook_audit_log
Statusproduction

Cross-links: salesmsg · feedback_salesmsg_api_first

Handler 4 — Twilio Voice + SMS (port 18797)

FieldValue
Port18797
Handler[[workspace/webhooks/twilio-voice-handler.js]]
Process managerPM2 (twilio, id:1)
Tunnel path(s)/sms, /sms/webhook, /sms/status, /voice, /voice/webhook, /voice/status, /voice/recording-complete, /voice/transcription
Sig verify✅ HMAC-SHA1(URL+params), dual-host (webhook.reri.co + Tailscale fallback URL both verified)
IP filterN/A
Dedup✅ processed_webhook_events 24h TTL
Audit log✅ webhook_audit_log
Statusproduction
10DLC flag⚠️ A2P 10DLC repeat-denial active — TCPA risk uncapped. See osil-twilio-10dlc-resubmission-2026-05-03
Rollback noteTailscale Funnel rollback active for /sms + /voice; dual-host verifier handles path correctly via CF; Tailscale rollback path UNTESTED

Cross-links: twilio · compliance-gates · cloudflare

Handler 5 — Gmail Push (port 18801)

FieldValue
Port18801
Handler[[workspace/webhooks/gmail-push-handler.js]]
Process managermanual / cron
Tunnel path/webhook/gmail-push
Sig verify⚠️ verify config — not fully hardened
IP filterN/A
Dedup⚠️ verify
Audit log⚠️ verify
Statusapproved-pending-harden

Cross-links: Gmail Push subscription (KB at sources/kb/google-workspace/)

Handler 6 — BlueBubbles iMessage (port 18802, Tailscale-only)

FieldValue
Port18802
Handler[[workspace/webhooks/imessage-handler.js]]
Process managersystemd imessage-webhook.service
Tunnel path/imessage — Tailscale ONLY (never in CF Tunnel)
Sig verify✅ query token ?token=BLUEBUBBLES_WEBHOOK_SECRET (constant-time)
IP filterTailscale topology (source: auroras-mac-mini / 100.93.7.6 per MagicDNS)
Dedup✅ webhook-dedup.js 24h TTL
Audit log✅ webhook-audit.js + /tmp fallback
Statuspending-deploy
NoteBlueBubbles has NO HMAC capability (KB WEBHOOKS.md §Authentication). Query token is only available auth mechanism.

Cross-links: aws (Aurora’s Mac mini on Tailscale)

Handlers 7–9 — Internal / secondary

HandlerPortDescriptionStatus
Discord-Lovable bridge18794Wildcard public ⚠️ — not in FUNNEL-REGISTRYsecurity-review needed
salesmsg-gateway.js18796Internal SMS gateway ⚠️ P0: hardcoded API key in unit filesecurity-review needed
Broadcast Audit UI18812Wildcard public ⚠️ — not in FUNNEL-REGISTRYsecurity-review needed

Sig verify methods by platform

PlatformMethodImplementation
HubSpotHMAC-SHA256(body) v1hubspot-handler.js verify middleware
DocuSignWAF IP allowlist (Cloudflare Pro)Cloudflare custom rule, 90-day rotation
OpenPhone/QuoHMAC(secret, ts.body)quo-handler-enhanced.js
SalesMsgQuery token ?secret=salesmessage-handler-v4-complete.js constant-time compare
TwilioHMAC-SHA1(URL+params)twilio-voice-handler.js dual-host
Gmail Push⚠️ Verify configNot fully configured
BlueBubblesQuery token ?token=Tailscale-only, constant-time
Make.comQuery/token param⚠️ Weaker than HMAC

Cloudflare Tunnel topology

Internet → webhook.reri.co (Cloudflare WAF)
    ├── /webhook/hubspot/* → :18790 (PM2 hubspot)
    ├── /webhook/openphone, /webhook/quo → :18792 (systemd openphone-webhook)
    ├── /webhook/salesmessage, /webhooks/salesmessage → :18793 (PM2 salesmsg)
    ├── /sms/*, /voice/* → :18797 (PM2 twilio)
    └── /webhook/gmail-push → :18801 (manual)

Tailscale Funnel srv1347501.tailb025a7.ts.net (fallback, unadvertised)
    ├── /sms, /voice, /webhook/hubspot, /webhook/openphone, etc. → same handlers
    └── /oauth/callback → :18790 (HubSpot OAuth one-time install)

Tailscale-Only (never public, topology-constrained)
    └── /imessage → :18802 (imessage-webhook.service, source: auroras-mac-mini)

Live state snapshot (2026-05-03)

MetricDocumentedLive (probed)DriftStatus
Total handlers96 (core ports active)−3gmail-push unconfirmed; internal handlers vary
Fully hardened handlers75−2gmail-push + make.com pending
security-audit-funnel.timerweeklylast fired 2026-04-276 days⚠️ STALE
DocuSign WAF rule90-day cyclelast checked 2026-04-27review pending
Handlers with plaintext creds01 (salesmsg-gateway unit file)⚠️ P0

How it’s used

  • Inbound event processing: all external events (deals, SMS, voice, emails) enter via these handlers
  • New provider onboarding: add entry to FUNNEL-REGISTRY FIRST → implement handler with all 4 invariants (sig verify, dedup, audit log, IP filter) → register port in port-registry → start service
  • Sig failure investigation: journalctl --user -u <unit> --since "1h ago" | grep sig
  • Dedup check: SELECT * FROM processed_webhook_events WHERE event_id = '<id>' in Supabase CCP
  • Security audit: node workspace/scripts/security-audit-funnel.js --dry-run → must report clean (or expected transient findings only)
  • Failure mode: handler down → events queued at provider → replay risk; sig verify off → replay attack vulnerability

Agents that touch this

  • _summary — consumes OpenPhone/Quo and SalesMsg events for deal dispatch
  • _summary — processes deal-detection events from HubSpot + OpenPhone
  • _summary — consumes HubSpot events for dispo pipeline

Skills that invoke this

Plans that govern this

Feedback rules

KB / source docs

  • README — Tunnel config, WAF rules, IP allowlist
  • WEBHOOKS — HubSpot webhook event shapes
  • WEBHOOKS — OpenPhone webhook event shapes
  • WEBHOOKS — SalesMsg webhook shapes (note: query token, not HMAC)
  • WEBHOOKS — Twilio HMAC-SHA1 verification

System maps

Per Wave 1 spec §7 cross-hub clusters:

  • hubspot — HubSpot provider (handler 1)
  • openphone-quo — OpenPhone/Quo provider (handler 2)
  • salesmsg — SalesMsg provider (handler 3)
  • twilio — Twilio provider (handler 4)
  • discord — Discord alert notifications
  • cloudflare — Tunnel layer (fronts all public handlers)

Open issues / TODOs

  • P0 — Run security-audit-funnel.js --dry-run manually (timer stale since 2026-04-27)
  • P0 — DocuSign WAF IP allowlist rotation check (90-day cycle overdue per last audit date)
  • P1 — Harden gmail-push handler (add sig verify + dedup + audit log per FUNNEL-REGISTRY invariants)
  • P1 — Add 18794, 18796, 18812 to FUNNEL-REGISTRY or explicitly reject (wildcard public, no sig verify)
  • P1 — Rotate salesmsg-gateway unit file credential (G-NO-PLAINTEXT-CREDS)
  • P2 — Test Twilio rollback via Tailscale Funnel (dual-host verifier untested on Tailscale path)
  • Remove HubSpot OAuth /oauth/callback from Tailscale Funnel once app installed on all portals

Recent activity

  • 2026-05-03: system hub created (W2-S4, Wave 2); security-audit-funnel.timer staleness flagged as P0
  • 2026-04-27: last security-audit-funnel.timer run (last known clean state)
  • 2026-04-22: BlueBubbles iMessage handler added to FUNNEL-REGISTRY (pending-deploy)
  • 2026-04-21: FUNNEL-REGISTRY created; all 4 providers migrated to webhook.reri.co via CF Tunnel v19