Skip to content
ALI HAITHAM·TECH·responds in <1h
  • Homestart here
  • Workcase studies, projects
  • Serviceswhat I will build for you
  • Writingessays, series
  • Traincourses, labs, cohorts
  • Aboutthe engineer behind this site
Sign inStart a project
ALI HAITHAM · TECH
  • Home↗
  • Work↗
  • Services↗
  • Writing↗
  • Train↗
  • About↗
Sign inStart a project
Online
ALI HAITHAM·TECH

Engineering studio. Damascus, GMT+3.

aliyosef.online

Studio

  • Work
  • Writing
  • Training
  • About
  • Contact me

Portal

  • Sign in
  • Open a ticket
  • Track project
  • My account

Resources

  • Docs
  • Status
  • Changelog
  • Brand kit
  • Privacy
  • Terms

Newsletter

Field notes and tech news. Weekly. No fluff.

Free. Unsubscribe anytime.

Find me elsewhere
© 2026 Ali Haitham Yosef. All rights reserved.Hand-built in React 19. No frameworks of frameworks.Last deployed · 2026-05-08All systems operational
Case 082025Backend Engineer

Junada WhatsApp Suite

WhatsApp broadcast and template automation for a regional e-commerce operator. Direct Meta Cloud API integration, 1.2M messages routed monthly at 99.9% deliverability.

RoleBackend Engineer
Year2025
StackNode.js, Meta Cloud API, WhatsApp API
Overview

About the project.

Junada is a WhatsApp broadcast and template automation suite I built for a regional e-commerce operator who was bleeding money on per-message platform fees. The system talks to the Meta Cloud API directly, manages template approval, and routes large broadcasts through a queue that respects per-customer rate limits. I designed and built the backend, the queue layer, and the admin tooling. It moves over a million messages a month without a third-party intermediary.

Outcome

What changed.

1.2M messages

messages routed per month

99.9%

deliverability

<300ms

API latency, p95

Challenge

What we walked into.

An e-commerce operator wanted to broadcast order updates and promotional messages to their customer base via WhatsApp without paying per-message platform fees forever.

Approach

What we did.

Direct integration with the Meta Cloud API, a Node.js queue that respects per-customer rate limits, and a template-management UI that mirrors WhatsApp's own approval flow so admins know upfront whether a draft will be accepted.

Outcome

What it became.

Routing 1.2 million messages per month at 99.9% deliverability with sub-300ms median dispatch latency.

IndustryE-commerce · CRM · Marketing automation
TypeWhatsApp broadcast platform + template lifecycle CMS
Timeline6 months · v1; ongoing operation
TeamSolo · backend engineer + DevOps + admin-UI engineer
Ownership

My role on this project.

Solo · 100% backend + queue + admin UI + Meta API integration. No SaaS layer (Twilio, MessageBird, 360dialog) sitting between the operator and Meta. Direct relationship with Meta Cloud API means margin retained, full template control, and no per-message middleman fees.

  • 01

    Backend engineer

    Node.js 20 + Fastify. Direct Meta Cloud API client, webhook handler for delivery receipts, template-status sync.

  • 02

    Queue + rate-limit engineer

    BullMQ on Redis. Per-customer rate-limit buckets respecting WhatsApp's tier system (250/1k/10k/100k msg/day depending on quality score).

  • 03

    Admin UI engineer

    Template builder mirroring Meta's approval form, broadcast scheduler, recipient list manager, delivery-rate dashboard with real-time updates.

  • 04

    DevOps + observability

    PM2, MongoDB Atlas, Sentry for error tracking, Grafana dashboards for delivery rate + queue depth.

In production

The numbers that matter.

  • 1.2M+Messages routed monthlySteady-state production volume; spikes during sale events.
  • 99.9%DeliverabilityMeta-confirmed delivered (not just dispatched). Failed sends auto-quarantined + retried after analysis.
  • <300msMedian dispatch latencyEnqueue → Meta API ack, measured at the broadcast worker.
  • $0Per-message middleware feeDirect Meta integration — only Meta's conversation pricing applies. No SaaS markup.
  • ~85%Template approval rateEstimated — admin UI catches the most common rejection causes before submission to Meta.
  • <2sWebhook delivery-receipt processingMeta webhook → DB update → dashboard refresh.
Why this was hard

What was actually broken.

WhatsApp messaging at scale forces a choice: pay Twilio/MessageBird/360dialog roughly $0.005-0.015 per message in middleware fees on top of Meta's conversation pricing — at 1M messages/month that is $5k-$15k/month going to a middleman that adds queue management + dashboards but holds your business hostage to their pricing. Or integrate Meta Cloud API directly, which means building the queue, the template-approval lifecycle, the delivery-receipt webhook handling, the rate-limit-tier compliance, and the dashboards yourself. The operator chose direct integration after running the math past Year 1.

Engineering challenges

The hard surface area.

  • 01WhatsApp rate-limit tier system (250 → 1k → 10k → 100k → unlimited messages/day depending on quality score) requires per-customer token bucket that respects the current tier AND auto-throttles when quality score dips.
  • 02Template approval lifecycle: drafts → submitted → in_review → approved/rejected. Admin UI must mirror Meta's rejection reasons exactly so operators iterate fast without submitting bad drafts.
  • 03Delivery receipts arrive async via webhooks for each message — at 40k messages/day that is 40k webhook hits. Must process all of them within 2 seconds to keep the dashboard live.
  • 04Recipient list management: WhatsApp requires opt-in confirmation per phone number; the platform must track consent status + per-phone delivery history to avoid silent quality-score damage from sending to unresponsive numbers.
  • 05Cost transparency: operators want per-broadcast cost in their currency BEFORE pressing send. Meta's pricing varies by recipient country + conversation category (utility, marketing, authentication, service). Calculator must match Meta's billing within ±2%.
Hard problems solved

Engineering wins worth naming.

01

Per-customer rate-limit bucket

Token bucket per WhatsApp Business Account (WABA), refilled at the rate matching the current tier. When tier downgrades (quality score drop), bucket immediately resets to new limit. No queue overflow.

02

Template approval-aware admin UI

Admin UI runs Meta's rejection-reason regex set CLIENT-SIDE before submit. Operators see warnings (e.g. "Marketing templates cannot contain phone numbers in the body") and edit before burning a submission slot.

03

Webhook idempotency

Meta retries failed webhook deliveries up to 24h. Same delivery receipt may arrive 5+ times. Idempotency key on (waba_id + message_id + status) prevents double-counting.

04

Cost-prediction engine

Pre-fetched Meta pricing matrix, refreshed daily. Per-recipient country lookup, conversation-category classification, currency conversion against operator base currency. ±2% accuracy verified against monthly Meta invoices.

System architecture

How the system is wired.

01 — Edge

Edge tier

CloudflareCDN · WAFProtects admin panel; webhook endpoint allowlisted to Meta IPs
NginxReverse proxy · TLSRoutes /api → Fastify, /webhooks/meta → dedicated webhook worker
02 — App

Application tier (Node.js)

Admin APIFastify + JWTOperator-facing CRUD: templates, broadcasts, recipients, dashboards
Meta clientCustom SDK · undiciDirect Cloud API integration; retry-with-backoff; tier-aware throttling
Webhook receiverFastify · signature verifyHMAC-SHA256 signature check before any DB write
Cost calculatorPricing matrix + Intl.NumberFormatPre-send estimate accurate to ±2% of actual Meta invoice
03 — Async

Async + queue tier

BullMQRedis-backed queuePer-WABA queue; tier-aware rate limit; auto-retry with backoff
Broadcast workerBullMQ consumer · 4 procsPops jobs, calls Meta, records ack, fires webhook update
Webhook processorBullMQ consumer · idempotentDelivery receipts → MongoDB update → real-time admin push
04 — Data

Data tier

MongoDB AtlasTemplates · broadcasts · recipientsSchemaless suits per-template variability; indexes on (waba_id, status)
Redis 7Queue · cache · rate-limitSingle Redis for queue + token-bucket counters + session cache
Why this stack

The decisions behind each choice.

Node.js + Fastify (backend)

  • Event-driven runtime is the natural fit for high-throughput webhook + queue I/O — 40k receipts/day with single-digit CPU.
  • Fastify outperforms Express by 2-3x on JSON throughput at the small request sizes WhatsApp webhooks produce.
  • Native async/await + Promise.all patterns make per-broadcast fan-out trivial.

BullMQ + Redis (queue)

  • Per-WABA queue names give natural per-customer isolation without separate Redis instances.
  • Built-in retry-with-backoff handles Meta's 429s without custom code.
  • Job priorities let urgent transactional messages cut in line ahead of bulk marketing broadcasts.

MongoDB (templates + broadcasts)

  • Templates have wildly varying structure (header media types, button counts, language overrides) — JSON-native storage avoids 5+ migrations per template feature.
  • Aggregation pipelines power the delivery-rate dashboard without an OLAP sidecar.

Direct Meta Cloud API (no middleware SaaS)

  • At 1M+ messages/month, middleware fees ($5k-$15k/month) exceed the cost of building the broker once.
  • Full control over template lifecycle, tier upgrades, and quality-score recovery — no SaaS layer hiding the levers.
  • Direct WABA ownership stays with the operator; switching providers later means swapping queue + dashboard, not migrating account state.
Lessons learned

What the build taught us.

  • Per-message middleware fees compound. At any meaningful volume, owning the broker pays for itself within a year.
  • WhatsApp's rate-limit tier system rewards good actors — but it punishes mistakes hard. Quality-score recovery takes weeks. Build the admin UI to prevent bad drafts before they ship, not just to react to rejections.
  • Webhook idempotency is not optional. Meta WILL retry. Plan for it from day one.
Visuals

From the project.

Continue reading
Previous caseHAEIFINNext caseKais Center
Build with us

Want something like this?

I take on a small number of engagements each quarter. Tell me what you have in mind.

Start the conversation→