Multi-tenant WhatsApp automation platform
A messaging SaaS handling automation, subscriptions and real-time notifications for thousands of concurrent conversations.
The problem
The product needed to run automated WhatsApp conversations for many business tenants at once, sync them with each tenant's CRM in real time, and stay inside Meta's per-number rate limits without dropping messages.
Challenges
- Meta Cloud API rate limits are per phone number, so throughput had to be shaped per tenant, not globally
- Webhook delivery is at-least-once — duplicate events had to be safe
- Tenants needed isolated data with a single deployable codebase
- Support staff needed to inspect a failing conversation without database access
What we built
- Multi-tenant messaging core with per-tenant configuration, numbers and templates
- Visual automation builder that compiles to a deterministic state machine
- Subscription and usage metering tied to message volume
- Real-time notification stream to the dashboard
- Support console with conversation replay and delivery timelines
Architecture
- NestJS modular monolith with clear module boundaries instead of premature microservices
- PostgreSQL with row-level tenant scoping enforced in a single data-access layer
- RabbitMQ queues per tenant priority class, with dead-letter queues for poison messages
- Redis for distributed rate limiting, conversation state caching and websocket presence
- Next.js dashboard, Docker images deployed to AWS with GitHub Actions
Key engineering decisions
Rate limiting in Redis, not in the queue
Queue-level throttling could not express per-number Meta limits. A Redis token bucket keyed by tenant phone number let workers stay generic while throughput stayed compliant.
Idempotency keys on every inbound webhook
Every Meta event is stored with its provider event ID before processing. Duplicate deliveries become no-ops instead of double-sent replies.
A modular monolith first
One deployable unit with strict module boundaries kept operational cost low, while the boundaries left an obvious extraction path if a module ever needed to scale alone.
Results
- Thousands of concurrent conversations handled without hitting provider rate limits
- Duplicate and out-of-order webhooks stopped causing double replies
- Support resolves most conversation issues from the console, without engineering
Request a set of drawings for your own project.
One business day for a reply from an engineer, not a sales pipeline. Tell us the problem and we'll tell you honestly if we're a fit.
