← blog
10 juillet 2026·2 min·2 vues

Une API WhatsApp interne avec Baileys (sans Chromium)

retour projetwhatsappdevopsnode.js
Une API WhatsApp interne avec Baileys (sans Chromium)

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.