Skip to content
JM.
Back to work

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

SMT architecture: GraphQL API, BullMQ scheduler and paced send queue to the WhatsApp Cloud API; status webhooks acknowledged fast, queued, processed, and relayed with retries.

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.

Next projectInstaPlug — Instagram Feed Widget