SMT — WhatsApp Marketing Platform
Architected and built from an empty repository: a distributed WhatsApp campaign engine with BullMQ-driven bulk sends, scheduling, and a webhook delivery system built for thousands of messages at once.
- Stack
- Node.js · BullMQ · GraphQL · PostgreSQL · Redis · WhatsApp API · Docker
The challenge
Businesses wanted to run marketing on WhatsApp the way they run it on email: design a template, pick an audience, schedule it, and measure what happened. The WhatsApp Business API makes that possible — but far from easy. Templates need approval. Sends are strictly rate-limited. Delivery status arrives asynchronously, through webhooks, at volume.
This was the first system I designed and built end to end — every service, every table, every queue — from an empty repository to production.
What I engineered
A complete distributed service platform, built from scratch:
- Template lifecycle management. Create and submit WhatsApp marketing templates, track approval status, and reuse them across campaigns.
- High-volume bulk campaigns on BullMQ. One campaign, a massive audience — sent now or on a schedule. Every send is queued through BullMQ and released at exactly the pace WhatsApp accepts, so even the largest campaign never hits the API as a burst.
- Built for concurrency. Many customers launching campaigns simultaneously was the normal case, not the edge case. Work is partitioned per campaign and per recipient batch, so no single campaign can starve the rest.
- Webhook delivery system. Inbound status webhooks — sent, delivered, read, failed — are acknowledged instantly, queued, and processed in the background, then relayed to customers' own endpoints with automatic retries.
- Campaign scheduling. Time-based campaign execution orchestrated by the same queue-driven core.
Architecture
GraphQL API → Node/Express services → PostgreSQL (Sequelize) for templates, campaigns, contacts, and message state → Redis + BullMQ powering scheduling, send queues, and webhook processing → WhatsApp Cloud API outbound, webhooks inbound. Fully containerised in Docker.
The decision that made the system hold up: acknowledge webhooks immediately, process them later. WhatsApp retries slow webhook responses — doing real work inside the request would have triggered duplicate processing under exactly the load that mattered most.
Impact
- A full production platform architected and delivered from zero
- Queue-governed throughput that respects WhatsApp's limits at any campaign size
- A fault-tolerant webhook pipeline with retries built in
What I took from it
Building from scratch meant owning every foundational decision — service boundaries, schema, queue topology, retry semantics — and then living with them in production. This is where queue semantics and idempotency stopped being theory and became instinct.