Envoyer un OTP ou une notification sur WhatsApp, c'est simple… jusqu'à ce que tu regardes le prix des API officielles et la complexité de leur validation. Pour mes projets (Mon Bara, TransitSoft), j'avais besoin d'un canal WhatsApp interne, léger, réutilisable. C'est WhatsApp Internal API : une brique unique que tous mes produits consomment via un SDK.
Baileys, sans Chromium
Beaucoup de solutions font tourner WhatsApp Web dans un Chromium headless — lourd, fragile, gourmand en RAM. J'ai choisi Baileys, qui parle le protocole WhatsApp directement en WebSocket, sans navigateur. Résultat : ça tourne sur un petit VPS sans y penser.
- Serveur : Express + Socket.IO + Baileys + BullMQ (port 4000)
- Dashboard : Next.js (créer une session, scanner le QR, générer les clés)
- packages/shared : types + schémas Zod + events socket — source de vérité
- packages/sdk : le client npm
@wa/sdk
Multi-sessions et clés par session
Chaque session = un numéro WhatsApp. On la crée depuis le dashboard, on scanne le
QR avec le téléphone, puis on génère une clé API affichée une seule fois. Un
projet consommateur ne voit jamais Baileys : il a juste une baseUrl et une clé.
Le rate limiting, c'est de la survie
WhatsApp bannit vite un numéro qui spamme. Toute émission passe donc par une file d'attente BullMQ rate-limitée (15 msg/min, configurable), avec retry automatique (3 tentatives, backoff) et une concurrence contrôlée. Les statuts remontent en temps réel via Socket.IO :
queued → sending → sent → delivered → read | failed
Un échec ? On le rejoue depuis le dashboard, ou il se re-enqueue tout seul.
Une ligne côté consommateur
C'est là que le SDK paie. Dans n'importe quel projet Node ≥ 18 :
import { WhatsAppClient } from "@wa/sdk";
const wa = new WhatsAppClient({ baseUrl, apiKey: process.env.WA_API_KEY! });
await wa.sendOtp("237655388662", "482913");
Le SDK est publié par la CI (GitLab) sur un tag sdk-vX.Y.Z, et le service se
déploie derrière Caddy (TLS auto) — le compose n'expose rien d'autre que le
localhost, postgres et redis restent internes.
Ce que j'en retiens
La meilleure décision a été d'en faire une brique interne unique plutôt que de recoller WhatsApp dans chaque projet. Une file d'attente + un rate limit + un SDK typé, et tous mes produits envoient des OTP sans réinventer la roue — ni risquer un ban.
Tu gères l'envoi de messages transactionnels (SMS, WhatsApp, email) comment de ton côté — service maison ou fournisseur tiers ? Et comment tu tiens les limites de débit ? Dis-moi.