Nouveau : HonkIO refuse désormais les numéros morts et fictifs avant qu'ils ne vous coûtent quoi que ce soit
Depuis le 1er septembre, un envoi vers un numéro 555, un code de test d'opérateur ou un numéro que trois échecs consécutifs d'opérateur ont déjà déclaré mort est refusé par une 422 au lieu d'être facturé. Ce qui a changé, pourquoi, et ce que cela implique pour votre logique de réessai.
Jusqu'à cette semaine, HonkIO considérait tout numéro mobile canadien bien formé comme un numéro qui valait la peine d'être essayé. Si vous nous demandiez de texter le +1 613 555 0100, nous le remettions à l'opérateur, l'opérateur nous répondait que personne n'habitait là, et vous payiez trois cents pour l'apprendre. Redemandez, et vous payiez de nouveau.
C'était défendable, dans un sens étroit. L'opérateur nous facture bel et bien la tentative, et nous répercutons les coûts d'opérateur plutôt que de les absorber. Mais cela produisait des factures que personne ne pouvait expliquer et n'arrêtait en rien un script en boucle. Le 1er septembre, nous avons donc livré deux changements qui refusent ces envois avant qu'ils ne coûtent quoi que ce soit à qui que ce soit.
Premier changement : les centraux derrière lesquels personne ne peut se trouver
Un numéro nord-américain a trois parties : un indicatif régional, un central et une ligne. Certains centraux sont réservés par le plan de numérotation et ne peuvent jamais être attribués à un abonné. Le bloc 555 est le plus connu, gardé pour le cinéma, la télévision et les services d'annuaire. Les codes N11 comme 411 et 911 sont des services, pas des personnes. 958 et 959 sont des codes de test des opérateurs. Les centraux qui commencent par 0 ou 1 ne sont tout simplement pas des centraux valides.
HonkIO refuse désormais tout envoi vers l'un d'eux par une 422 RESERVED_DESTINATION avant qu'il n'atteigne l'opérateur. Aucune ligne de message n'est créée, rien n'est facturé, et la réponse nomme le central et explique pourquoi :
HTTP/1.1 422 Unprocessable Entity
{
"code": "RESERVED_DESTINATION",
"message": "Le numéro de destination appartient à un central réservé (555-XXXX, codes N11, codes de test des opérateurs) derrière lequel aucun abonné ne peut se trouver. Rien n’a été envoyé ni facturé; les détails précisent le central.",
"statusCode": 422,
"details": {
"part": "NXX",
"code": "555",
"reason": "Exchange 555 is reserved for fictional use and information services and cannot receive SMS. Nothing was sent or charged."
}
}Cela s'applique en mode test comme en mode réel, et c'est la partie la plus susceptible de vous surprendre. Beaucoup de tests d'intégration utilisent des numéros 555 précisément parce qu'ils sont fictifs. Ils échoueront désormais immédiatement avec le code ci-dessus. Utilisez plutôt une clé de test : une clé de test n'atteint jamais un opérateur et ne facture jamais rien, quel que soit le numéro visé.
Les indicatifs régionaux réservés, comme 555 ou 911 dans les trois premiers chiffres, étaient déjà refusés comme numéros non canadiens et le sont toujours. Rien n'a changé de ce côté.
Deuxième changement : les numéros que le réseau a déjà abandonnés
Le deuxième changement est une liste que HonkIO tient désormais des numéros qui sont, du point de vue des opérateurs, morts. Personne ne la rédige. Elle se construit d'elle-même à partir des accusés de livraison. Chaque accusé de livraison est un verdict de l'opérateur : livré, échoué ou non livré. Quand un numéro accumule trois échecs consécutifs en 30 jours, de la part de n'importe quel client HonkIO, il est inscrit sur la liste pour 90 jours.
Tant qu'il y figure, un envoi vers ce numéro est refusé par une 422 UNDELIVERABLE_NUMBER. Encore une fois, aucune ligne et aucuns frais. La réponse vous dit combien d'échecs l'y ont mené, quand c'est arrivé et quand nous réessaierons :
HTTP/1.1 422 Unprocessable Entity
{
"code": "UNDELIVERABLE_NUMBER",
"message": "Ce numéro est inscrit comme injoignable; l’envoi a été refusé sans frais. Les détails indiquent pourquoi il a été inscrit et quand il sera réessayé automatiquement.",
"statusCode": 422,
"details": {
"failures": 3,
"listed_at": "2026-09-02T14:07:11.000Z",
"expires_at": "2026-12-01T14:07:11.000Z",
"last_error_code": "30003"
}
}Quatre-vingt-dix jours, c'est à peu près le temps pendant lequel les opérateurs canadiens conservent un numéro débranché avant de le réattribuer, de sorte qu'une inscription expire à peu près au moment où le numéro pourrait de nouveau avoir un propriétaire. Nous le réessayons alors une fois et repartons de zéro.
La liste est partagée par toute la plateforme, parce qu'un numéro mort l'est pour tout le monde, mais elle est anonyme. On vous dit que le numéro est inscrit; on ne vous dit jamais qui d'autre l'a essayé.
Ce qui n'inscrit pas un numéro sur la liste
- Une panne d'opérateur. Si l'opérateur est injoignable ou répond par une erreur de serveur, l'envoi est refusé par une 503 CARRIER_UNAVAILABLE, rien n'est facturé, et la tentative n'est pas un verdict sur le numéro.
- Un solde vide ou une erreur de facturation de votre côté. Cela concerne votre compte, pas le destinataire.
- Un message encore en attente. Seul un accusé final compte.
- Une livraison entre-temps. Une seule livraison réussie remet la série à zéro, si bien qu'un numéro simplement capricieux met plus de temps à être inscrit qu'un numéro disparu.
- Les codes de vérification. Ils vont à votre propre téléphone, que vous venez de saisir, et contournent donc entièrement la liste.
- Les envois en mode test. Le mode test ne consulte jamais la liste.
Les lignes fixes et les numéros VoIP ont leur propre refus gratuit, 422 NOT_A_MOBILE_NUMBER, lui aussi nouveau depuis le 1er septembre. Notre profil d'opérateur est réservé au mobile, si bien qu'un numéro incapable de recevoir un SMS est écarté avant tout envoi.
Ce que cela implique pour votre code
Ces trois refus sont définitifs pour le numéro visé. Réessayer est la seule chose qui n'aidera pas, et une boucle de réessais contre un numéro inscrit se heurte désormais aussi au plafond par destinataire de 30 messages à l'heure et 100 par jour, qui répond 429 RECIPIENT_RATE_LIMITED. Donc :
- Lisez le champ code, pas seulement le statut. Une 422 avec RESERVED_DESTINATION, UNDELIVERABLE_NUMBER ou NOT_A_MOBILE_NUMBER veut dire : arrêtez, marquez le contact et passez au suivant.
- Gardez les numéros 555 hors de vos jeux de données de test. Pointez plutôt une clé de test vers n'importe quel numéro bien formé.
- Quand vous réessayez vraiment, après un délai dépassé ou une 503, envoyez un en-tête Idempotency-Key. Un réessai qui en porte un ne peut jamais devenir une deuxième facturation.
- Les messages non livrés que l'opérateur a acceptés restent facturés. Cela n'a pas changé, parce que l'opérateur nous les facture toujours. Ce qui a changé, c'est que nous cessons de lui remettre des numéros qu'il a déjà refusés trois fois.
Le compromis
La liste compte les échecs d'opérateur sans demander pourquoi l'opérateur a échoué. La plupart des échecs sont des numéros morts, mais certains relèvent du filtrage de contenu, et un numéro légitime qui reçoit trois messages filtrés en un mois sera inscrit aux côtés des numéros morts. Nous avons choisi d'accepter cela plutôt que de deviner à partir des codes d'erreur des opérateurs, qui ne sont pas assez fiables pour trier. Deux soupapes existent : le seuil et la fenêtre sont ajustables, et notre équipe peut retirer un numéro plus tôt si vous nous dites qu'il est réel. Après quelques mois de données, nous reverrons si trois est le bon chiffre.
Les règles complètes, y compris chaque code et les champs qu'il transporte, se trouvent dans la section sur les limites d'envoi de la documentation. Si l'un de ces refus vous paraît un jour erroné, dites-le-nous. Chaque inscription conserve le code d'opérateur qui l'a motivée, et nous pourrons donc la reprendre avec vous.
HonkIO