Webhooks
Messaging — Webhooks
Inbound provider events (a customer replies, a receipt updates) arrive at the
UnifiedWebhookController, base path /api/v1/messaging/webhook. These
routes are public (no admin JWT) — they're authenticated by per-provider
signatures instead.
Endpoints & signature validation
| Route | Verification |
|---|---|
POST /messaging/webhook/waha | x-webhook-hmac — HMAC (sha256) of the raw body with WAHA_HMAC_SECRET, compared with timingSafeEqual |
GET /messaging/webhook/whatsapp-cloud | Hub verify: hub.verify_token == WHATSAPP_CLOUD_VERIFY_TOKEN → echoes hub.challenge |
POST /messaging/webhook/whatsapp-cloud | x-hub-signature-256 — sha256= HMAC over raw body with WHATSAPP_CLOUD_APP_SECRET |
GET/POST /messaging/webhook/instagram | Hub verify vs INSTAGRAM_VERIFY_TOKEN; x-hub-signature-256 with FACEBOOK_APP_SECRET |
GET/POST /messaging/webhook/tiktok | tiktok-signature (t=<ts>,s=<hmac>) — HMAC-sha256 of <ts>.<rawBody> with TIKTOK_APP_SECRET |
Facebook Messenger events arrive through the shared Facebook webhook entry point
and are routed into Messaging. In NODE_ENV=development with no secret set,
verification is skipped (and warns). A bad signature throws 401.
Routing (factory pattern)
WebhookRouterService.route(providerType, payload) dispatches to a per-provider
factory that picks the right handler:
| Provider | Factory → handlers |
|---|---|
| WAHA | WebhookEventHandlerFactory → MessageHandler, MessageAckHandler, SessionStatusHandler, CallHandler, MessageEditedHandler, MessageRevokedHandler, PresenceUpdateHandler, LabelChatsHandler, … |
| WhatsApp Cloud | WaCloudChangeHandlerFactory (by change.field) → MessagesChangeHandler, TemplatesChangeHandler |
FbMessagingHandlerFactory → FbMessageHandler, FbDeliveryHandler, FbReadHandler | |
IgMessagingHandlerFactory → IgMessageHandler, IgDeliveryHandler, IgReadHandler | |
| TikTok | TiktokEventHandlerFactory → TiktokMessageHandler, TiktokReadHandler |
Each handler writes to the DB, then publishes to Redis so the WebSocket gateway pushes the update to connected clients. Handlers are idempotent — providers retry.
These are provider → Corteksa webhooks. To receive Corteksa → your app events (e.g. a record changed), see the Receive webhooks recipe.