/Resources
/Backend
/How to Contribute
/Webhook Service Setup

Webhook Service Setup

Learn how to set up, configure, and run the Reloop webhook service locally.

The Webhook Delivery Service is an ElysiaJS microservice that manages the scheduling, formatting, cryptographical signing, and dispatching of outbound event webhooks to developer callback URLs. It listens for system-wide events and processes delivery retries using BullMQ.

Prerequisite First

Before configuring the Webhook Service, make sure you've completed the base Local Development Setup (installed Bun, configured the hosts file, and started the Docker container stack).


Quick Start

Dependencies are handled globally at the root directory. You can start the Webhook Service development server instantly:

# Start the dev server with hot reloading
bun be:webhook:dev
cd apps/backend/webhook
bun dev

Once running, the Webhook Service will listen locally on port 8013. You can query it via Caddy at https://local.reloop.sh/api/webhook ๐ŸŽ‰


Service Information

  • Directory Location: apps/backend/webhook/
  • Local Listening Port: 8013 (configurable with PORT env variable)
  • Unified Access Route: https://local.reloop.sh/api/webhook
  • Primary Tech Stack: ElysiaJS, BullMQ, Redis, PostgreSQL, NATS
  • Dependencies: Relies on PostgreSQL (to query subscriber callback targets) and Redis (to schedule and process BullMQ delivery jobs).

Environment Configuration

The Webhook Service environment variables are defined in apps/backend/webhook/.env. If you ran bun env:setup at the root, your .env is already configured:

# Database & Cache Configurations
PG_URL=postgresql://reloop:reloop123@localhost:5432/reloop
REDIS_URL=redis://:reloop123@localhost:6379

# Server Gateway Configuration
PORT=8013
BASE_URL="https://local.reloop.sh"
NODE_ENV=development
NODE_TLS_REJECT_UNAUTHORIZED=0

# Event Bus Broker
NATS_URL=nats://localhost:4222

Reference Table

VariableRequiredDefault ValueDescription
PG_URLYESpostgresql://...PostgreSQL database connection string.
REDIS_URLYESredis://...Redis connection URL used by BullMQ to schedule delivery jobs.
PORTYES8013Local port number the Elysia app listens to on the host.
BASE_URLYEShttps://local.reloop.shMain application domain (used for cookie validations).
NATS_URLYESnats://localhost:4222Connection URL for NATS event bus messaging.
NODE_TLS_REJECT_UNAUTHORIZEDNO0Allows self-signed certificates in local development mode.
NODE_ENVYESdevelopmentActive environment scope (development or production).

Development Commands

All workspace operations should be executed from the monorepo root directory using Turborepo filters:

CommandActionScope
bun be:webhook:devStart the Webhook dev server with hot reloadingDevelopment
bun run --filter=webhook buildCompile the Webhook service for productionProduction
bun run --filter=webhook startRun the compiled production build locallyProduction
bun run --filter=webhook check-typesVerify TypeScript type-safetyCode Quality

Database Schema & Relationships

The relational subscriber endpoints configuration, event subscriptions, payload archives, and dispatch delivery logs are defined inside packages/db/src/schema/webhook.ts.

Enums

EnumValuesDescription
webhook_statusactive ยท paused ยท disabled ยท failedWebhook subscription delivery status
webhook_delivery_statuspending ยท success ยท failed ยท retryingSpecific event dispatch execution status

webhook Table

Holds user-configured outbound endpoints, secret signing tokens, and execution aggregations.

ColumnTypeDefaultDescription
idtextwh_{cuid}Primary Key
namevarchar(255)โ€”Friendly name label for the endpoint
urltextโ€”Recipient HTTP target URL destination
secrettextโ€”Cryptographic HMAC-SHA256 signature signing token
organizationIdtextโ€”Foreign Key โ†’ organization.id
userIdtextโ€”Foreign Key โ†’ user.id
statuswebhook_statusactiveActive subscription configuration state
customHeadersjsonbnullKey-value dictionary of custom HTTP headers sent (Record<string, string>)
rateLimitEnabledbooleantrueThrottling toggle constraint
maxRequestsPerMinuteinteger60Request rate volume ceiling
maxRetriesinteger3Maximum retry attempts for failed dispatches
successCountinteger0Cumulative successful deliveries count
failureCountinteger0Cumulative failed delivery attempts count
consecutiveFailuresinteger0Current series of consecutive failures before auto-disabling

webhook_delivery Table

High-fidelity transactional logs tracking the chronological attempts, network payloads, durations, and response status codes for every event dispatch.

ColumnTypeDefaultDescription
idtextwhde_{cuid}Primary Key
webhookIdtextโ€”Foreign Key โ†’ webhook.id
webhookEventIdtextnullForeign Key โ†’ webhook_event.id
eventTypetextโ€”Semantic event type (e.g. domain.verified)
statuswebhook_delivery_statuspendingDispatch attempt resolution state
requestUrltextโ€”Dispatched network URL
requestHeadersjsonbnullSent headers including security signature
requestBodyjsonbโ€”Sent JSON body payload
responseStatusintegernullReceived HTTP response status code
responseBodytextnullReceived body output stream
attemptNumberinteger1Increment sequence of current attempt
durationMsintegernullRequest completion time (ms)

Other Webhook Tables

  • webhook_event_subscription: Link table mapping webhooks to specific event filters.
  • webhook_event: Relational event log storing the canonical payload structure and workspace context representing an asynchronous event trigger.

Interactive API Docs (Swagger)

The Webhook Service publishes dynamic Swagger documentation directly from ElysiaJS. To test endpoints and query API structures:

  1. Open your browser and navigate to the interactive Swagger playground at https://local.reloop.sh/api/webhook/openapi (or http://localhost:8013/api/webhook/openapi directly).
  2. Use the interactive Swagger UI playground to run queries and inspect request schemas.

Core Operational Mechanics

  1. Event Capture: The service captures real-time campaign dispatches, click logs, and delivery notifications by subscribing to core NATS subjects (kumomta.event.*, tracking.*).
  2. Subscription Matcher: For every captured event, the PostgreSQL database is queried to find matching customer webhook configurations in the webhook_subscription table.
  3. Queue Scheduling: If an active subscriber matches the trigger event, a delivery payload is constructed and scheduled in BullMQ (webhook-delivery-queue) in Redis.
  4. Signed Outbound Attempt: A background BullMQ worker pulls the job, signs the payload string using the customer's shared subscription secret (x-reloop-signature header), and dispatches it over HTTP POST.
  5. Robust Retry Loop: If the destination server returns a non-2xx response, the worker registers a fail state, scheduling automated retries using exponential backoff (configured in queues/webhook.queue.ts).