Passerelle WhatsApp Web
La passerelle est le service qui tient les sessions WhatsApp Web de vos cartes SIM : une SIM = un numéro = une session. Elle tourne à côté de Trackily, jamais dedans. Trackily lui demande d'envoyer ; elle lui renvoie les accusés, les réponses et les STOP. Et c'est elle qui impose un rythme d'envoi que personne ne peut accélérer.
Ce que ça coûte, à lire avant d'installer
- C'est contraire aux conditions d'utilisation de WhatsApp. Un numéro peut être banni sans préavis, parfois en quelques heures s'il écrit à des gens qui ne l'ont jamais contacté. Il n'y a ni recours, ni support, ni récupération : le numéro est perdu.
- N'appairez jamais un numéro dont vous avez besoin — celui du service client, le vôtre, celui imprimé sur les colis. Une SIM dédiée, par numéro.
- Les garde-fous de Trackily s'appliquent sans exception : consentement, STOP, suppressions, plafonds par compte, licence. Rien n'est contourné parce que « ce n'est pas l'API ». Écrire à froid reste ce qui fait bannir.
- La passerelle n'a aucune fonction de diffusion. Un message = un destinataire = un appel, et le rythme s'applique à chacun. Ce n'est pas un oubli.
Pourquoi un service à part
Une session WhatsApp Web, c'est une connexion permanente, un état d'authentification sur disque et une bibliothèque lourde. Rien de tout cela n'a sa place dans Trackily, et surtout : une session qui tombe ne doit pas emporter le tracker. D'où un service séparé, une passerelle par instance de Trackily, plusieurs sessions dedans.
Trackily Passerelle (réseau privé)
envoi, appairage, état ── HTTP + jeton ──────▶ sessions WhatsApp Web (une par SIM)
/webhook/wa/<clé> ◀── HTTP + signature ───── accusés, messages entrants, STOP
Deux chemins réseau doivent donc exister : Trackily doit joindre la passerelle (adresse interne), et la passerelle doit joindre l'URL publique de Trackily (pour poster ses événements).
Installer
La passerelle se déploie comme un conteneur Docker ; un Dockerfile et un exemple docker-compose.exemple.yml l'accompagnent.
Générez deux secrets, et gardez-les hors de tout dépôt :
openssl rand -hex 32 # → PASSERELLE_JETON openssl rand -base64 32 # → PASSERELLE_CLE (32 octets)Déployez le service dans le même réseau privé que Trackily, à partir de l'exemple de
docker-compose.Ne publiez aucun port. La passerelle ne doit être joignable que par Trackily, sur le réseau privé. Publiée sur Internet, son jeton deviendrait la seule chose entre le monde et un numéro qui envoie.
Montez un volume persistant sur le dossier des sessions (
/app/sessionsdans l'image). Sans lui, chaque redéploiement redemande un QR pour chaque SIM.Dans Trackily, réglez l'URL publique (Settings (Paramètres) → General → Advanced Configuration → Public URL), puis créez un compte par SIM (voir Comptes). L'URL de la passerelle est
http://<nom du service>:3300.
Les réglages
| Variable | Défaut | Rôle |
|---|---|---|
PASSERELLE_JETON |
— | Obligatoire. Le jeton exigé sur toutes les routes sauf la sonde de santé. C'est aussi le « Jeton de la passerelle » de chaque compte dans Trackily. Sans lui, la passerelle refuse de démarrer ; en dessous de 24 caractères, elle le signale dans ses journaux. |
PASSERELLE_CLE |
— | Obligatoire. 32 octets en base64. Chiffre (AES-256-GCM) l'état d'authentification des sessions sur le disque. Sans elle, ou mal formée, la passerelle refuse de démarrer : un dossier de session en clair, c'est un compte WhatsApp à qui le copie. |
PORT |
3300 |
Port d'écoute. |
SESSIONS_DIR |
./sessions |
Dossier des sessions (/app/sessions dans l'image) — à monter en volume. |
LOG_NIVEAU |
info |
Niveau des journaux. |
C'est tout. Il n'existe aucun réglage du rythme d'envoi (voir plus bas).
Sauvegarder
PASSERELLE_CLEperdue = toutes les SIM à réappairer. Sauvegardez-la avec vos autres secrets.- Le volume des sessions, lui, EST le compte WhatsApp : une copie de ce volume, avec la clé, permet d'envoyer depuis le numéro. Traitez-le comme une base de mots de passe. L'un sans l'autre ne vaut rien ; les deux ensemble valent vos numéros.
- Les journaux (sortie standard) ne contiennent ni l'état d'authentification, ni les secrets, ni le contenu des messages.
Surveiller et mettre à jour
GET /healthz, la seule route ouverte sans jeton, répond{ ok, sessions: { total, connectees } }sans nommer aucune session. L'image s'en sert comme sonde de santé.- À l'arrêt (signal
SIGTERM, celui d'un redéploiement), la passerelle ferme proprement : d'abord les requêtes, puis la boîte de sortie, puis les sessions. Ce qui n'a pas été posté à Trackily repart au démarrage suivant. - Une seule passerelle par volume. Deux passerelles sur le même dossier de sessions se disputent chaque numéro ; après trois reprises de session d'affilée, la passerelle abandonne et marque la session « déconnectée » plutôt que de se battre — c'est ainsi qu'un numéro finit banni.
Appairer, et les états d'une session
L'appairage se fait depuis Trackily (Comptes → Appairage) : par QR, ou par code sur le téléphone qui porte la SIM. Le QR vit 60 secondes. Une fois appairé, laissez le téléphone allumé et connecté : WhatsApp Web est un appareil lié, pas un compte séparé.
| État | Ce qui se passe |
|---|---|
| absente | Jamais appairée. |
| appairage | QR ou code affiché, la passerelle attend. |
| connectee | Le numéro envoie. |
| deconnectee | L'appareil a été retiré depuis le téléphone (l'état d'authentification est effacé), ou une seconde passerelle se dispute la session. Il faut réappairer. |
| bannie | Terminal. WhatsApp a fermé le numéro. Rien ne tente de le reconnecter ni de le réappairer : se rebrancher sur un numéro banni, c'est confirmer à WhatsApp qu'il a affaire à un robot. |
Une coupure réseau ordinaire ne change pas l'état : la passerelle se reconnecte seule, après 2 s, 10 s, 30 s, 2 min, puis toutes les 5 min, sans jamais abandonner. Pendant ce temps, elle répond « indisponible » aux envois, que Trackily retente plus tard.
Une session déjà connectée ne se réappaire pas par-dessus : il faut d'abord la Déconnecter, sciemment. Un double clic sur « Appairer » ne lance pas deux appairages.
Les événements remontent, toujours
Chaque accusé, chaque message entrant, chaque STOP est d'abord écrit sur le disque, puis posté à Trackily par lots. Tant que Trackily ne l'a pas accepté, l'événement reste sur le disque et repart après 5 s, 30 s, 2 min, 10 min, puis toutes les heures — sans limite de tentatives, y compris après un redémarrage de la passerelle. Un STOP reçu pendant un déploiement de Trackily n'est donc pas perdu. Trackily déduplique : un événement reçu deux fois ne compte qu'une fois.
Chaque lot est signé avec le « Secret des événements » du compte (HMAC-SHA256 de l'horodatage et du corps). Trackily refuse un lot mal signé, ou dont l'horodatage s'écarte de plus de 5 minutes de son horloge : gardez les horloges des deux machines à l'heure.
Ce que la passerelle relaie, et ce qu'elle tait :
- les statuts (parti, livré, lu, échoué) des seuls messages qu'elle a envoyés elle-même, pendant 7 jours après l'envoi ;
- les messages entrants des seuls numéros auxquels la SIM a déjà écrit, ou était en train d'écrire (mémoire de 180 jours et de 20 000 numéros au plus par session) — les conversations privées d'un téléphone ne remontent pas dans Trackily ;
- jamais les groupes, les statuts WhatsApp, ni les messages sans texte (une image seule, une réaction).
WhatsApp Web ne transmet aucune préférence de désabonnement : sur cette voie, c'est le mot STOP qui fait foi (voir Suppressions).
Pourquoi le rythme ne se règle pas
Ce qui fait bannir un numéro n'est pas un quota publié : c'est un comportement — une cadence régulière à la milliseconde, une rafale au premier soir d'un numéro neuf, un message qui arrive sans que personne n'ait « écrit ». La passerelle impose donc, par session :
| Garde | Valeur |
|---|---|
| Délai entre deux sollicitations de WhatsApp | aléatoire, de 4 à 12 secondes, tiré à chaque fois : un intervalle régulier est la signature d'un robot |
| Envois simultanés | un seul à la fois |
| Plafond horaire | 40 sollicitations par heure glissante |
| Échauffement, selon l'ancienneté de l'appairage | jour 1 : 20 · jour 2 : 40 · jour 3 : 70 · jour 4 : 100 · jour 5 : 150 · ensuite, plus de plafond d'échauffement (le plafond horaire reste) |
| « En train d'écrire… » | affiché avant chaque message, le temps de le taper, trois secondes au plus |
| Vérification du destinataire | avant « en train d'écrire… » : la passerelle demande d'abord si le numéro a un compte WhatsApp |
Trois précisions qui comptent :
- Ce qui est compté, c'est la sollicitation, pas le succès. Vérifier un numéro sans WhatsApp coûte au numéro ce qu'un envoi lui coûte : un refus entame le délai et les plafonds comme un envoi. Une liste pleine de numéros morts épuise le quota du jour — et abîme la SIM.
- Le « jour » d'échauffement est un jour d'ancienneté, pas une date : un numéro appairé à 23 h 50 n'a pas droit au quota du lendemain dix minutes plus tard. Réappairer remet le compteur au jour 1. Les compteurs survivent à un redémarrage de la passerelle.
- Pas de file d'attente cachée. Si l'attente estimée d'un envoi dépasse 30 secondes, la passerelle refuse tout de suite ; Trackily le reprend plus tard, sans compter de tentative.
Ces valeurs sont des constantes, dans le code de la passerelle. Il n'existe aucune route, aucune variable d'environnement, aucun réglage pour les changer, et il n'y en aura pas. La raison est simple : un bouton « envoyer plus vite » est un bouton « bannir ce numéro » — il serait poussé le jour d'une promotion, sur la plus grosse liste, et la SIM tomberait au pire moment. Un réglage qu'on ne peut pas mal régler est un réglage qu'on retire.
Les plafonds du compte dans Trackily (40 messages par heure et 100 destinataires uniques par jour par défaut) et l'échauffement que Trackily applique de son côté s'ajoutent à ceux de la passerelle : le plus strict gagne, toujours.
Ce que Trackily fait des refus de la passerelle
| Refus de la passerelle | Ce que fait Trackily |
|---|---|
echauffement, debit (plafond ou file trop longue) |
Reporte l'envoi, sans compter de tentative |
passerelle_indisponible (reconnexion), delai |
Retente plus tard ; un envoi peut-être parti n'est jamais renvoyé deux fois |
| Un 502 ou 504 sans code (le proxy placé devant la passerelle, pas elle : elle n'en émet jamais sans code) | Échec envoi_incertain, sans nouvel essai : le proxy n'a pas eu la réponse, le message est peut-être parti. Les autres envois de cette SIM attendent 5 minutes, sans compter de tentative |
numero_inexistant |
Échec, et le numéro est bloqué pour tout (« Numéro invalide ») |
destinataire_bloque |
Échec, et le numéro est bloqué pour le marketing (« Désinscription signalée par le fournisseur ») |
session_absente, session_deconnectee, session_bannie, jeton refusé |
Échec, et le compte passe en erreur avec la raison. Si la SIM est rangée dans un groupe, les messages encore en file repartent d'une autre SIM quand le routage leur retient un groupe qui connaît leur modèle (la liste vise le groupe, une règle, ou un seul groupe possible pour ce métier) ; sinon ils échouent sur cette SIM |
Dans le doute, rien n'est renvoyé. La passerelle retient chaque envoi pendant 24 heures sous son identifiant : un même envoi redemandé rend le même message sans le renvoyer. Un envoi dont l'issue est inconnue (parti chez WhatsApp, accusé perdu) est rendu en erreur à chaque nouvelle demande, sans être renvoyé : Trackily le laisse en échec (envoi_incertain) dès cette réponse, sans le retenter — jamais en double chez le client.
Cela vaut aussi quand la passerelle est arrêtée brutalement pendant un envoi : juste avant de confier le message à WhatsApp, elle écrit sur son disque la réservation de cet envoi et le numéro du destinataire. Au redémarrage, elle relit l'envoi comme « issue inconnue » — il n'est pas renvoyé —, et la réponse de ce client (un STOP, un clic sur la confirmation) est bien relayée. Si elle ne peut pas écrire sur son disque (volume plein ou en lecture seule), elle n'envoie pas : elle répond passerelle_indisponible, et Trackily retente plus tard.
Un numéro banni
Rien à réparer. Le compte passe en erreur dans Trackily. Si la SIM bannie était rangée dans un groupe, ses messages encore en file repartent d'une autre SIM quand le routage leur retient un groupe qui connaît leur modèle (la liste vise le groupe, une règle, ou un seul groupe possible pour ce métier). Sinon — SIM sans groupe, ou aucun groupe retenu — chacun de ces messages reste attaché au numéro banni et échouera à son heure : changer le compte de la liste ne les déplace pas, car un message programmé garde son numéro. Annulez-les depuis le journal si vous ne voulez pas les voir échouer un à un. Remplacez la carte SIM par un nouveau compte, appairez-le, et laissez-le s'échauffer.
Voir aussi
- Comptes — créer un compte WhatsApp Web et l'appairer
- Rotation — répartir la charge entre plusieurs SIM
- Suppressions — le STOP sur la voie SIM
- WhatsApp Marketing — les deux voies, côte à côte