Event-Driven Integrations in Regulated SaaS
Designing resilient webhook, notification, and integration pipelines in a healthcare SaaS environment.
Context
As our healthcare platform expanded, we integrated with multiple external systems:
- AWS SNS for SMS notifications (including timezone-aware scheduling)
- Worldpay for payment webhooks
- Insurance authorization systems via webhook callbacks
- SignalWire for fax delivery
- Internal domain events across intake, billing, and authorization modules
Each integration introduced uncertainty: delayed responses, duplicate webhooks, transient failures, and third-party downtime.
In a regulated environment, missed events or double processing are not minor bugs — they are compliance and financial risks.
The challenge was to design event pipelines that assumed failure as normal behavior.
Architectural Direction
I adopted an event-driven pattern using:
- AWS SQS for queue-based decoupling
- Lambda workers for async processing
- Structured logging + DynamoDB for event persistence
- Correlation IDs for traceability
- Retry classification (temporary vs permanent failure)
The goal was not just asynchronous execution — but controlled reliability under uncertainty.
System Design
Design principle: external systems are unreliable; internal systems must be deterministic.
Core Patterns Implemented
- Validation-first webhook ingestion
- Persistence-before-processing
- Retry with exponential backoff
- Dead-letter queues for permanent failure
- Correlation IDs across all downstream logs
Notification System (SMS & Fax)
SMS via AWS SNS
Designed support for:
- Scheduled notifications across time zones
- Clinic-level timezone configuration
- Deferred message publishing
- Retry handling on SNS delivery failure
Scheduling logic normalized all timestamps to UTC internally, then converted per clinic configuration.
Fax via SignalWire
Fax integration followed the same async ingestion pattern:
- Submission request persisted
- Delivery status webhook processed
- Failure states reconciled against internal message record
Fax delivery, often slow and unpredictable, was treated as an eventually consistent event.
Observability & Traceability
Reliability without observability is guesswork.
I implemented:
- Structured logs persisted to DynamoDB
- Correlation IDs per event
- CloudWatch log streaming
- Event-level tracing across Lambda execution chains
This allowed us to trace a payment webhook from ingestion → retry → final state mutation deterministically.
Alerting is not yet implemented, but structured logging makes future monitoring straightforward.
Failure Modes
Even when not fully implemented, I designed the system with these failure modes in mind:
- Duplicate webhook delivery
- Partial processing failure mid-transaction
- Third-party downtime
- Message size limits (future guardrail consideration)
- Event replay for recovery
- Idempotent processors for safe reprocessing
Designing for these upfront reduced architectural rework later.
Tradeoffs
Why SQS instead of direct processing?
Direct webhook → DB write would have been simpler but fragile under burst traffic and retry storms. Queue decoupling provided buffering and controlled concurrency.
Why not Kafka?
Current scale does not justify the operational overhead. SQS + Lambda provides sufficient throughput and simpler maintenance.
Why persist before processing?
Persisting webhook payloads before business logic guarantees replay capability and forensic audit traceability.
Outcomes
- Reliable handling of duplicate webhooks
- Reduced operational incidents caused by transient failures
- Deterministic audit trails for compliance reviews
- Clean decoupling between external systems and core domain logic
- Extensible foundation for future event streaming evolution
The system assumes failure as normal — and remains predictable under it.
Reflection
What worked
Persist-before-process and retry classification were the most impactful decisions. They turned unpredictable third-party behavior into deterministic internal workflows.
What I'd improve
- Formal idempotent event processor abstraction
- Replay tooling for selective event reprocessing
- Alerting on DLQ growth and retry exhaustion
- Message size validation guardrails
Future direction
- Introduce event versioning contracts
- Add DLQ monitoring and automated escalation
- Evaluate Kafka or EventBridge if event volume grows significantly
- Implement structured event schema registry