Référence
Messagerie et politique anti-bannissement
Les plafonds, classes de destinataires et codes d'erreur qu'evaluateSendPolicy applique à chaque envoi WhatsApp.
Le WhatsApp d'une boutique est un vrai numéro de téléphone sur WhatsApp Web ; WhatsApp bannit les numéros qui se comportent comme des spammeurs. evaluateSendPolicy (src/libs/services/WhatsAppSendPolicy.ts) refuse au nom du tenant avant tout envoi effectif, sur chaque route capable de mettre un message sur le fil — pas seulement l'API.
Classes de destinataires
Chaque envoi 1:1 est classé avant que les plafonds ci-dessous ne soient vérifiés :
| Classe | Signification |
|---|---|
known | correspond à une ligne CustomerModel, ou le numéro a déjà écrit à la boutique |
declared | pas connu, mais le tenant l'a déclaré via POST …/contacts/consented et la déclaration est toujours active (ni révoquée, ni expirée) |
cold | ni l'un ni l'autre — un véritable inconnu |
group | le destinataire est un groupe WhatsApp (@g.us), jamais known/declared/cold |
Plafonds (1:1)
| Règle | Par défaut | Code |
|---|---|---|
| Contenu | ≤ 4096 caractères, ≤ 1 média, texte ou média requis | MESSAGE_TOO_LONG / TOO_MANY_MEDIA / EMPTY_MESSAGE |
| Désabonnement | le dernier message entrant du destinataire était STOP/ARRÊT/DÉSABONNER/UNSUBSCRIBE | RECIPIENT_OPTED_OUT |
| Montée en puissance (jours depuis la connexion de la session WhatsApp) | j0–2 : 20/jour · j3–6 : 50 · j7–13 : 100 · j14+ : 250 | DAILY_CAP_REACHED |
| Horaire | max(10, plafond quotidien ÷ 6) | HOURLY_CAP_REACHED |
| Destinataires froids | 10 % du plafond quotidien, minimum 5 | COLD_RECIPIENT_CAP_REACHED |
| Destinataires déclarés | budget propre, configurable par le tenant — distinct de celui des « froids », ne déborde pas dessus | DECLARED_RECIPIENT_CAP_REACHED |
| Par destinataire | ≤ 3 messages / 24h, ≥ 10 min d'écart sauf s'il a répondu depuis | RECIPIENT_RATE_LIMITED |
| Motif en masse | texte identique envoyé à plus de 20 numéros distincts en 1h | BULK_PATTERN_BLOCKED |
Les tenants peuvent ajuster coldPerDay/declaredPerDay et les réglages associés, dans un plancher et un plafond fixés par la plateforme, depuis Paramètres → Messagerie ; une valeur hors de [plancher, plafond] est rejetée côté serveur, jamais simplement plafonnée en silence.
Plafonds (groupes)
Envoyer à un groupe utilise un budget entièrement séparé de celui du 1:1, basé sur groupsPerDay/groupPerRecipient24h, parce qu'un groupe n'est pas une personne :
| Règle | Code | |
|---|---|---|
| L'appelant doit fournir le contexte du groupe (nombre de participants, statut admin, indicateur annonce) | GROUP_CONTEXT_REQUIRED | |
| Le numéro de la boutique doit administrer le groupe — requis pour chaque groupe, pas seulement ceux en mode « annonces », car le désabonnement ne peut pas fonctionner par membre et la simple appartenance n'est pas un consentement à la diffusion | GROUP_NOT_ADMINISTERED | |
Plafond quotidien pondéré : une « part » de groupsPerDay par tranche de GROUP_SIZE_UNIT participants (arrondi au supérieur, minimum 1) — un groupe de 200 membres coûte plus qu'un groupe de 5, car il touche plus de monde | GROUP_DAILY_CAP_REACHED | |
| Par groupe | ≤ groupPerRecipient24h messages / 24h | RECIPIENT_RATE_LIMITED |
GET /shops/{idOrName}/groups renvoie isAdmin/announce par groupe, ce qui permet à l'appelant de filtrer et d'anticiper un refus probable avant de tenter un envoi — mais c'est la politique ci-dessus qui fait réellement autorité ; le champ canSend de la route est indicatif.
Appliqué dans le bot quel que soit l'appelant
Le destinataire doit exister sur WhatsApp (rejected, code RECIPIENT_NOT_ON_WHATSAPP) ; un seul envoi à la fois par boutique avec un intervalle aléatoire de 6 à 20 secondes entre les envois ; une présence « en train d'écrire » (composing) affichée avant chaque message ; une pause de 15 minutes de toute la file d'attente de la boutique sur un signal de limitation venant de WhatsApp lui-même ; et en cas de perte de session, chaque message en file échoue avec WHATSAPP_SESSION_LOST et le canal est signalé jusqu'à la reconnexion. Si le WhatsApp propre à une boutique est déconnecté, certains envois peuvent passer par le pool partagé de la plateforme à la place, accompagnés d'une attribution visible « envoyé via OmniManager » — jamais silencieusement au nom du tenant.
Bonne pratique : écrivez à des personnes qui s'y attendent, variez la formulation, étalez les envois sur la journée, et respectez immédiatement les désabonnements et les réponses.