A microservices-based webhook delivery platform built with Java, Spring Boot, PostgreSQL, Redis, Kafka, Docker, and React. The project demonstrates practical backend infrastructure patterns: tenant API keys, endpoint and subscription management, idempotent event ingestion, Kafka-based asynchronous delivery, HMAC webhook signatures, retry scheduling, dead-letter replay, rate limiting, and a Docker Compose demo environment.
- Tenant and API key bootstrap flow
- HTTPS webhook endpoint management
- Event subscription management
- Idempotent event ingestion
- Kafka-based delivery job publishing
- HMAC-SHA256 webhook request signing
- Delivery attempt history
- Retry queue with manual retry and cancel actions
- Dead-letter queue with clear and replay actions
- Redis-backed gateway rate limiting
- Flyway-managed PostgreSQL schema
- React dashboard for local demos
- Backend and frontend test/build checks
flowchart LR
dashboard[React Dashboard] --> gateway[API Gateway]
subgraph gateway[API Gateway]
auth[Tenant API Key Auth]
admin[Admin Bootstrap Auth]
cors[CORS]
limit[Redis Rate Limiting]
proxy[Service Routing]
end
gateway --> management[Webhook Management Service]
gateway --> ingestion[Event Ingestion Service]
gateway --> delivery[Delivery Service]
gateway --> scheduler[Scheduler Service]
management --> postgres[(PostgreSQL)]
ingestion --> postgres
delivery --> postgres
scheduler --> postgres
ingestion --> kafka[(Kafka)]
scheduler --> kafka
kafka --> delivery
delivery --> target[Webhook Endpoint]
The dashboard talks to the API gateway. The gateway authenticates requests, applies rate limiting, and routes tenant APIs to the correct Spring service. Events are stored by the ingestion service and published to Kafka as delivery jobs. The delivery service consumes jobs, signs outbound webhook requests, records attempts, and schedules retries. The scheduler republishes due retries. Exhausted deliveries are stored in the dead-letter queue and can be replayed from the dashboard.
Start the full local stack:
docker compose up -d --buildThe Compose demo starts PostgreSQL, Flyway, Redis, Kafka, all Spring services, and the React dashboard.
Open:
Dashboard: http://localhost:3000
API gateway: http://localhost:8080
Check the gateway health endpoint:
curl http://localhost:8080/actuator/healthCreate a tenant from the dashboard, or load repeatable demo data:
docker compose --profile seed up seed-demoDemo dashboard credentials:
Tenant ID: 11111111-1111-1111-1111-111111111111
API key: demo-api-key
Then:
1. Add a reachable HTTPS webhook endpoint.
2. Add a subscription for an event type such as order.created.
3. Send a test event.
4. Select the event to inspect its payload and delivery attempts.
5. Open the retry and dead-letter queues to retry, cancel, clear, or replay failed deliveries.
Run the smoke test:
node scripts/smoke-test.mjsUse a custom webhook URL for the smoke test:
WEBHOOK_URL="https://example.com/webhooks" node scripts/smoke-test.mjsPowerShell:
$env:WEBHOOK_URL = "https://example.com/webhooks"
node scripts/smoke-test.mjsStop the demo:
docker compose downLocal defaults live in docker-compose.yml. Copy .env.example when you want to override ports, credentials, admin API key, or rate limits:
Copy-Item .env.example .envCommon values:
API_GATEWAY_PORT=8080
DASHBOARD_PORT=3000
POSTGRES_PORT=5432
REDIS_PORT=6379
KAFKA_PORT=9092
ADMIN_API_KEY=local-admin-key
GATEWAY_RATE_LIMIT_REQUESTS_PER_MINUTE=120
Each delivery request includes signature headers generated with the endpoint secret:
X-Webhook-Event-Id
X-Webhook-Event-Type
X-Webhook-Timestamp
X-Webhook-Signature
The signature is an HMAC-SHA256 digest of:
timestamp + "." + rawBody
The dashboard shows each endpoint secret and a Node.js verification example.
POST /tenants: create tenant with admin API keyPOST /tenants/{tenantId}/api-keys: create tenant API keyGET /tenants/{tenantId}/endpoints: list webhook endpointsPOST /tenants/{tenantId}/endpoints: create webhook endpointGET /tenants/{tenantId}/subscriptions: list subscriptionsPOST /tenants/{tenantId}/subscriptions: create subscriptionPOST /tenants/{tenantId}/events: ingest eventGET /tenants/{tenantId}/attempts: list delivery attemptsGET /tenants/{tenantId}/retries: list retry queuePOST /tenants/{tenantId}/retries/{retryId}/dispatch: retry nowGET /tenants/{tenantId}/dead-lettered-events: list dead lettersPOST /tenants/{tenantId}/dead-lettered-events/{deadLetterId}/replay: replay dead letter
- Authentication is API-key based for the MVP. A production system would typically add user accounts, OAuth/OIDC, scoped tokens, and key rotation.
- Webhook endpoint validation is intentionally strict and rejects hosts that cannot be resolved.
- Retry policy is fixed in service configuration rather than editable per endpoint.
- Kafka topics are auto-created in the local demo.
- The dashboard is a local portfolio/demo UI rather than a multi-user admin product.
- Docker Compose is intended for local demonstration, not hardened production deployment.
- Add user login and role-based tenant access.
- Add endpoint secret rotation.
- Add per-endpoint retry policy configuration.
- Add OpenTelemetry tracing across services.
- Add Prometheus metrics dashboards.
- Add pagination for large tenants.
- Add Kubernetes or Helm deployment examples.
Run backend tests:
cd backend/services
mvn testRun frontend checks:
cd frontend/dashboard
npm install
npm run buildRun the dashboard dev server:
cd frontend/dashboard
npm run devValidate Docker Compose:
docker compose configMIT License
Copyright (c) 2026 Eren Karakuş