Déduplication des SMS A2P : éviter les messages répétés sans bloquer les notifications légitimes
Un guide opérationnel pour distinguer les doublons techniques, les nouvelles tentatives contrôlées et les messages intentionnellement répétés, avec des clés d’idempotence, des fenêtres par cas d’usage et une traçabilité auditable.

Quel problème la déduplication résout-elle, et que ne doit-elle pas faire ?
La déduplication des messages SMS A2P réduit les envois répétés issus de demandes dupliquées, de nouvelles tentatives réseau, d’événements concurrents ou d’une incertitude après une réponse incomplète d’une API. Son objectif n’est pas d’empêcher toute répétition : elle doit éviter qu’une même intention métier produise plusieurs SMS indésirables, sans bloquer un renvoi légitime, une nouvelle alerte ou une communication consentie ayant un objectif distinct.
Le principe technique est l’idempotence. Une opération idempotente conserve le même effet prévu, qu’elle soit traitée une ou plusieurs fois. En messagerie, cela exige que l’application puisse reconnaître que deux demandes représentent la même intention avant de créer deux envois indépendants.
Une déconnexion avant la réception de la réponse de la plateforme ne prouve pas que l’envoi n’a pas été créé. Dans ce cas, créer un autre message sans rapprocher l’état peut entraîner un doublon. La politique doit conserver un identifiant d’idempotence propre, le persister et l’utiliser pour consulter ou rapprocher le résultat avant d’émettre un second envoi.
- Ne traitez pas la déduplication comme un blocage global par numéro de téléphone.
- Ne supposez pas qu’un accusé de réception d’API, un statut en file d’attente ou un événement d’envoi confirme la réception sur le terminal.
- Appliquez la décision à l’intention métier et à l’état du cycle de vie, et non uniquement au texte du SMS.
- Définissez des exceptions explicites et auditables pour les renvois demandés, les changements matériels de contenu ou les incidents.

Les trois cas à distinguer
Une politique utile commence par classer le motif de répétition. Les trois cas peuvent sembler identiques dans l’historique d’un destinataire, mais ils exigent des décisions différentes.
Le doublon technique survient lorsque la même intention est traitée plus d’une fois : par exemple, deux demandes concurrentes avec la même clé, une nouvelle tentative après la perte de la réponse, ou la répétition d’un événement provenant d’une file d’attente. Il doit normalement être supprimé lorsqu’un envoi est actif ou déjà créé pour la même intention.
La nouvelle tentative contrôlée est une action délibérée relevant d’une politique définie. Elle peut être nécessaire lorsque l’état précédent indique un échec, une non-livraison ou un résultat incertain, mais elle doit utiliser la même corrélation métier, les mêmes limites de fréquence et les mêmes règles d’éligibilité. Elle ne doit pas être confondue avec une réexécution aveugle d’une requête.
Un message légitimement répété correspond à un nouvel objectif, événement, défi ou autorisation. Une confirmation de commande et une alerte ultérieure concernant une modification de cette commande peuvent être adressées au même numéro et avoir un texte similaire, mais elles ne correspondent pas au même événement métier.
- Doublon technique : même intention, même clé, répétition indésirable.
- Nouvelle tentative contrôlée : même intention, nouvelle action autorisée par une règle d’état et de temps.
- Répétition légitime : nouvelle intention ou changement matériel vérifiable.

Concevez une clé de déduplication fondée sur l’intention
La clé doit représenter une unité précise d’intention métier. Le numéro de destination est nécessaire, mais insuffisant. Il doit être stocké et comparé dans une représentation internationale normalisée conforme au plan E.164, afin d’éviter que les différences de format local, les espaces, les tirets ou les préfixes produisent des clés différentes pour une même destination.
Comme base, une clé peut combiner la destination normalisée, l’objectif, l’identifiant de l’événement métier, l’expéditeur ou le profil d’envoi, ainsi qu’un identifiant de corrélation. Le modèle ou sa version peut être ajouté lorsqu’il aide à distinguer des communications matériellement différentes. Dans les systèmes distribués, il est également utile de conserver une clé d’idempotence générée par l’application et stable durant les nouvelles tentatives de cette même opération.
N’utilisez pas le corps du SMS comme seule clé. Les messages dynamiques changent selon les montants, les dates, les noms ou les références. Pour l’authentification, le texte peut contenir des secrets différents pour une même transaction ou des messages similaires pour des défis distincts. Deux OTP d’apparence similaire ne doivent pas être considérés comme équivalents sans connaître le défi, la tentative ou l’événement d’authentification auquel ils appartiennent.
- Destination normalisée au format international.
- Objectif : authentification, alerte, confirmation, campagne ou autre domaine défini.
- Identifiant d’événement : commande, incident, session, défi ou transaction.
- Expéditeur ou profil d’envoi, lorsqu’il fait partie de l’intention.
- Version du modèle ou classification du contenu, si elle est pertinente.
- Identifiant de corrélation et d’idempotence persistant.
Appliquez des fenêtres temporelles par cas d’usage, et non une fenêtre universelle
La fenêtre de déduplication est la période durant laquelle deux demandes ayant la même intention sont considérées comme candidates à la suppression ou au rapprochement. Il n’existe pas de durée universelle correcte : elle doit être définie selon l’objectif, le risque, l’expérience utilisateur et le cycle de vie attendu du message.
Pour les OTP et les autres secrets d’authentification, la politique doit être liée à la transaction d’authentification et au secret spécifique. Un secret ne doit être accepté qu’une seule fois durant sa période de validité. Le NIST indique qu’une authentification hors bande doit être considérée comme non valide si elle n’est pas achevée dans les 10 minutes ; cette limite n’impose pas que la fenêtre opérationnelle de suppression soit de 10 minutes, mais elle évite de traiter l’authentification comme un processus ouvert indéfiniment.
Pour les alertes transactionnelles, les confirmations et les communications consenties, la fenêtre doit refléter l’événement. Une confirmation répétée de la même commande peut être supprimée tant que le même événement et la même version sont en attente ou déjà traités. Toutefois, une modification matérielle de la commande, un nouvel incident ou une demande de renvoi vérifiable doit être évalué comme une nouvelle condition, et non comme un doublon automatique.
- OTP : liez la décision au défi et au secret, et non uniquement au destinataire ou au texte.
- Alertes : utilisez l’identifiant d’incident, l’état ou l’événement à l’origine de la notification.
- Confirmations : distinguez la première confirmation d’une modification ultérieure du même processus.
- Campagnes consenties : séparez les événements et les règles de fréquence de la déduplication technique.
Utilisez des états de décision et une machine à états
Une déduplication sûre ne se limite pas à répondre par oui ou non. Il est préférable d’utiliser des états de décision explicites : autoriser, supprimer, examiner et remplacer un message en attente. Chaque état doit être soutenu par une machine à états qui distingue au minimum les nouvelles demandes, les messages en attente d’envoi, envoyés, livrés, non livrés, échoués et à résultat inconnu.
Autoriser signifie qu’il n’existe pas de correspondance équivalente dans le cadre de la politique applicable, ou qu’une exception autorisée transforme la demande en nouvelle intention. Supprimer signifie qu’une opération équivalente existe déjà et que son effet doit être conservé. Examiner est réservé aux conflits de données, aux exceptions à risque élevé ou aux résultats ambigus qui ne doivent pas être résolus par une règle automatique.
Remplacer un message en attente peut être utilisé uniquement lorsque la politique autorise le remplacement d’un message qui n’a pas encore quitté l’état d’attente, et que la plateforme ou l’architecture contrôle cette transition de manière fiable. Il ne faut pas supposer qu’un message déjà envoyé, même marqué comme envoyé par un fournisseur, puisse être retiré ou remplacé.
- Autoriser : nouvelle intention ou exception valide.
- Supprimer : même intention dans la fenêtre applicable et avec un état empêchant un nouvel envoi.
- Examiner : conflit de corrélation, données incomplètes ou exception à risque.
- Remplacer en attente : uniquement avant l’envoi effectif et avec un contrôle de l’état.
Gérez la concurrence, l’incertitude et les callbacks asynchrones
Deux demandes identiques peuvent arriver simultanément depuis des processus différents. La protection doit intervenir avant la création de deux messages : utilisez une réservation atomique ou une contrainte d’unicité portant sur la clé de déduplication et la fenêtre applicable. L’opération doit renvoyer la décision et la référence à l’enregistrement existant lorsque cela s’applique.
Lorsqu’une réponse API est perdue ou qu’une déconnexion survient, conservez le résultat comme incertain. Avant de renvoyer le message, consultez ou rapprochez l’état à l’aide de la clé d’idempotence, de l’identifiant de corrélation ou de l’identifiant externe disponible. Si le résultat ne peut pas être déterminé, appliquez une règle de risque documentée au lieu de supposer que la première tentative a échoué.
Les callbacks de statut sont des événements asynchrones du cycle de vie. Ils peuvent arriver tardivement ou dans un ordre différent de celui attendu. Ils doivent être validés conformément au mécanisme proposé par la plateforme et traités de façon tolérante aux changements de paramètres et de séquences. Un statut en file d’attente indique une acceptation pour traitement ; un statut envoyé ne confirme pas non plus uniformément la livraison sur le terminal. Même un DLR de livraison doit être interprété selon la sémantique contractuelle et technique de la route, sans le présenter comme une preuve indépendante de lecture par l’utilisateur.
- Réservez la clé avant de créer l’envoi afin d’éviter les conditions de concurrence.
- Conservez l’état inconnu lorsque la réponse est incertaine.
- Rendez le traitement des callbacks idempotent.
- N’abaissez pas des états terminaux à cause d’événements tardifs ou réordonnés sans règle explicite.
- Distinguez l’acceptation API, le traitement, l’envoi et la livraison signalée.
Enregistrez chaque suppression afin qu’elle puisse être expliquée et examinée
Une suppression qui ne peut pas être expliquée devient un risque opérationnel. Le journal doit permettre de reconstituer quelle demande a été reçue, à quel message ou à quelle intention elle a été comparée, quelle règle a pris la décision et à quel moment la fenêtre empêchant une nouvelle création expirera.
Conservez la clé d’idempotence et de déduplication, les identifiants de corrélation internes et externes, l’objectif, la destination normalisée, l’état précédent et le nouvel état, la règle appliquée, l’horodatage, l’expiration de la fenêtre et la référence au message existant. Lorsqu’une exception ou une revue manuelle intervient, enregistrez le responsable, la justification et le résultat.
Les données d’audit doivent respecter des politiques adaptées d’accès, de minimisation et de conservation. Évitez d’enregistrer les secrets d’authentification en clair. Pour les OTP, il est particulièrement important que la traçabilité permette de relier l’événement sans exposer le secret hors bande.
- Motif de l’autorisation, de la suppression, de l’examen ou du remplacement.
- Clé et corrélation de la demande et du message existant.
- État connu du cycle de vie et source de l’état.
- Règle, version de politique et expiration appliquées.
- Responsable et justification pour les exceptions manuelles.
- Données minimales nécessaires au diagnostic et à l’audit.
Définissez des exceptions sans en faire une voie de contournement
Les exceptions doivent être prédéfinies, vérifiables et laisser une trace. Un changement matériel de contenu, un nouvel événement métier, un changement de canal autorisé, un incident opérationnel ou une demande de renvoi vérifiable peuvent justifier qu’une demande ne soit pas traitée comme un doublon.
En matière d’authentification, générer un nouveau secret et renvoyer un secret existant sont deux décisions distinctes. Le secret accepté doit pouvoir être utilisé une seule fois tant qu’il est valide. De plus, générer un nouveau secret ne doit pas réinitialiser le contrôle des tentatives échouées lorsque celui-ci s’applique. La déduplication ne doit pas affaiblir les contrôles de sécurité ni remplacer la limitation des tentatives.
N’utilisez pas les exceptions pour dépasser les limites de fréquence, masquer des erreurs d’intégration ou répéter des messages commerciaux sans une base de consentement et une politique applicable. La déduplication technique doit coexister avec les règles de consentement, d’exclusion, de fréquence et de contenu, sans les remplacer.
- Changement matériel vérifiable du contenu ou de l’état.
- Nouvel objectif ou nouvel événement métier.
- Changement de canal autorisé et traçable.
- Renvoi demandé et vérifiable par l’utilisateur.
- Incident avec procédure d’approbation et enregistrement.
- Ne réinitialisez jamais les contrôles de tentatives uniquement parce qu’un nouvel OTP est créé.
Questions fréquentes
Un message ayant le même texte est-il toujours un doublon ?
Non. Le même texte peut appartenir à des événements différents, et des textes différents peuvent représenter la même intention. La décision doit se fonder sur la destination normalisée, l’objectif, l’événement métier, la corrélation, l’état et la fenêtre applicable.
Un accusé de réception API confirme-t-il que l’utilisateur a reçu le SMS ?
Non. L’acceptation d’une demande ou le statut en file d’attente confirme que le message est entré en traitement, et non qu’il est arrivé sur le terminal. Les statuts ultérieurs doivent être interprétés selon leur sémantique et ne constituent pas une confirmation de lecture en SMS.
Comment traiter un OTP renvoyé ?
Il doit être lié à la transaction d’authentification et au secret concerné. Renvoyer le même secret et en générer un nouveau relèvent de politiques différentes. Un secret accepté ne doit pouvoir être utilisé qu’une seule fois durant sa période de validité.
Que se passe-t-il si la réponse de la plateforme d’envoi est perdue ?
Conservez le résultat comme incertain, gardez la clé d’idempotence et rapprochez l’état avant de créer un autre envoi. La perte d’une réponse ne prouve pas que la demande initiale n’a pas été appliquée.
Quelles métriques aident à détecter une mauvaise configuration ?
Examinez le taux de suppression par objectif, les doublons observés, les nouvelles tentatives échouées, les messages supprimés qui ont finalement nécessité un renvoi, les réclamations, les erreurs de corrélation et les cas de revue manuelle. Analysez à la fois les faux positifs, où un message légitime a été bloqué, et les faux négatifs, où un doublon a été autorisé.
Sources consultées
- E.164: The international public telecommunication numbering planInternational Telecommunication Union (ITU-T)
- NIST SP 800-63B-4: AuthenticatorsNational Institute of Standards and Technology (NIST)
- RFC 9110: HTTP SemanticsIETF / RFC Editor
- Messages resourceTwilio Documentation
- Outbound Message Status in Status CallbacksTwilio Documentation
- Message Status StreamTwilio Documentation
- Authentication Cheat SheetOWASP Foundation