Vérification de numéro

Confirmer qu'un numéro de téléphone appartient bien à votre utilisateur, par un code à usage unique envoyé sur WhatsApp.

L'API de vérification envoie un code à 6 chiffres sur WhatsApp, puis vous dit si le code saisi par l'utilisateur est le bon. MailPulse génère le code, l'envoie par le transport WhatsApp de votre organisation, compte les tentatives et gère l'expiration : votre application ne voit jamais le code.

Prérequis

  • Une clé API MailPulse (mp_live_* ou mp_test_*), créée dans Plateforme › Clés API et intégrations. Même authentification que POST /api/v1/messages.
  • Une instance WhatsApp Evolution connectée pour l'organisation. Sinon l'API répond 409. WhatsApp Cloud API (Meta) n'est pas encore pris en charge pour les codes : voir Limites de WhatsApp Cloud API.
Authorization: Bearer mp_live_xxx
Content-Type: application/json

Envoyer un code

POST /api/v1/verifications
curl -X POST $MAILPULSE_URL/api/v1/verifications \
  -H "Authorization: Bearer $MAILPULSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"channel":"whatsapp","to":"+2250700000000","locale":"fr","reference":"inscription_42"}'
ChampObligatoireDescription
channelouiwhatsapp, seul canal disponible.
toouiNuméro au format international (+225… ou 00225…). Espaces, points et tirets acceptés.
localenonfr (par défaut) ou en, langue du message. Toute autre valeur est refusée.
referencenonVotre identifiant, 191 caractères au plus, renvoyé tel quel.
sender_idnonUn des numéros de l'application de la clé (GET /api/v1/whatsapp/numbers). Absent : le numéro par défaut, ou un autre numéro WhatsApp Web de l'application si le défaut est sur Meta.

Réponse 201 :

{
  "id": "cmf8x2k0p0000abcd1234efgh",
  "status": "pending",
  "channel": "whatsapp",
  "to_masked": "+225 07 ** ** ** 00",
  "reference": "inscription_42",
  "expires_at": "2026-09-23T10:10:00.000Z",
  "created_at": "2026-09-23T10:00:00.000Z",
  "approved_at": null
}

L'utilisateur reçoit : « Votre code de vérification est 123456. Il expire dans 10 minutes. Ne le partagez avec personne. »

Si le fournisseur ne confirme pas l'envoi (délai dépassé, erreur de transport), la réponse reste 201 et la vérification reste pending : le message a pu partir, et un code qui arrive en retard fonctionne. Seul un refus certain du fournisseur donne 502, ou 503 whatsapp_sature s'il limite les envois.

Vérifier le code saisi

POST /api/v1/verifications/{id}/check
curl -X POST $MAILPULSE_URL/api/v1/verifications/cmf8x2k0p0000abcd1234efgh/check \
  -H "Authorization: Bearer $MAILPULSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code":"123456"}'

Code correct, réponse 200 :

{ "id": "cmf8x2k0p0000abcd1234efgh", "status": "approved" }

Code refusé, réponse 422 :

{ "id": "cmf8x2k0p0000abcd1234efgh", "status": "pending", "error": "code_invalide" }
statuserrorSignification
pendingcode_invalideMauvais code, l'utilisateur peut réessayer.
max_attemptstrop_de_tentatives5 mauvais codes : la vérification est bloquée, envoyez-en une nouvelle.
expiredexpirePlus de 10 minutes se sont écoulées.
canceledexpireUn nouveau code a été envoyé au même numéro, seul le dernier est valable.
approvedexpireCode déjà utilisé : un code ne valide qu'une seule fois.
failedexpireLe code n'a jamais pu être envoyé.

Un code mal formé (autre chose que 6 chiffres) est refusé en 422 avec field_errors, sans consommer de tentative.

Consulter une vérification

GET /api/v1/verifications/{id}
curl $MAILPULSE_URL/api/v1/verifications/cmf8x2k0p0000abcd1234efgh \
  -H "Authorization: Bearer $MAILPULSE_API_KEY"

Renvoie le même objet que l'envoi, avec le statut courant : pending, approved, expired, max_attempts, canceled ou failed. Une vérification d'une autre organisation répond 404, comme un identifiant inconnu.

Renvoyer un code

Pour renvoyer un code, refaites un POST /api/v1/verifications pour le même numéro. La vérification en attente précédente passe en canceled et son code cesse de fonctionner.

Vérification inversée (recommandée)

Un code envoyé par MailPulse part vers quelqu'un qui n'a jamais écrit au numéro : c'est le signal que WhatsApp surveille le plus sur un numéro WhatsApp Web. En mode inversé, c'est la personne qui envoie le code au numéro de votre application depuis un lien wa.me. Rien ne part de MailPulse, et le numéro d'où vient le message prouve qu'il lui appartient.

curl -X POST $MAILPULSE_URL/api/v1/verifications \
  -H "Authorization: Bearer $MAILPULSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "whatsapp", "to": "+2250700000000", "mode": "reverse" }'

Réponse 201 : l'objet habituel avec "mode": "reverse", plus message (le texte que la personne enverra, code compris) et wa_link, le lien qui ouvre WhatsApp sur le numéro de l'application avec ce texte déjà saisi. Ces deux champs ne sont rendus qu'une fois.

Affichez le lien, puis consultez la vérification (GET) toutes les quelques secondes jusqu'à approved. Quand le message arrive du bon numéro avec le bon code, MailPulse approuve la vérification et répond à la personne sur WhatsApp. Ce message n'est pas transmis au chatbot de l'application.

  • Seul le numéro WhatsApp Web propre à l'application peut recevoir ces codes : sinon, 409 inverse_indisponible.
  • POST /verifications/{id}/check refuse une vérification inversée (409 verification_inverse) : le code a été affiché à celui qui l'a demandé, le recopier ne prouve rien.
  • Un message du bon numéro avec un mauvais code consomme une tentative, comme un code mal saisi.

Limites

LimitePortée
1 envoi par minutepar numéro destinataire et par organisation
3 envois par heure, 5 par jourpar numéro destinataire et par organisation
1 code toutes les 5 s, 6 par minute, 80 par heure, 500 par jourpar numéro expéditeur
1 code toutes les 10 s, 3 par minute, 30 par heure, 150 par jourpar numéro expéditeur connecté par QR code depuis moins de 30 jours
30 minutes sans codepar numéro expéditeur, après une limitation de WhatsApp
20 envois par heurepar clé API
100 envois par heurepar organisation
30 envois par minutepar organisation, partagés avec les messages WhatsApp de POST /api/v1/messages

Au-delà, réponse 429 avec l'en-tête Retry-After. Deux envois simultanés pour la même organisation ne s'attendent pas : le second reçoit aussi un 429, avec retry_after à 1 seconde.

{ "error": "trop_de_demandes", "retry_after": 42 }

Les limites par numéro expéditeur ne comptent que les codes envoyés par MailPulse : une vérification inversée n'en consomme aucune. Chaque envoi compte, y compris un envoi en échec ou remplacé. Les codes partent du même numéro WhatsApp que vos messages API : ils consomment la même limite par minute, pour ne pas exposer ce numéro à un blocage.

Erreurs

HTTPerrorCause
401Invalid API keyClé absente, révoquée ou plan sans accès API.
404verification_introuvableIdentifiant inconnu pour cette organisation.
409whatsapp_indisponibleAucune instance Evolution connectée, ou organisation sur WhatsApp Cloud API.
409inverse_indisponibleMode inversé demandé, mais la clé n'envoie pas depuis le numéro WhatsApp Web propre à son application.
409verification_inverseVérification de code sur une vérification inversée : elle ne s'approuve que par le message WhatsApp.
409destinataire_refuseLe destinataire a répondu NON ou STOP au numéro de l'application de la clé. Aucun code n'est créé.
422Validation failedNuméro absent, non international ou de longueur impossible : field_errors.to.
422Validation failedAutre champ invalide, détail dans field_errors.
429trop_de_demandesLimite atteinte, attendre retry_after secondes.
502envoi_echoueRefus certain du fournisseur : numéro sans compte WhatsApp ou requête refusée (HTTP 4xx, hors 408 et 429). Rien n'est parti, la vérification est enregistrée en failed.
503whatsapp_satureLe fournisseur WhatsApp limite les envois (HTTP 429). Rien n'est parti, la vérification est enregistrée en failed. Réessayez plus tard ; retry_after et l'en-tête Retry-After sont présents quand le fournisseur donne un délai.
503verification_indisponibleService non configuré côté MailPulse.

Suivi dans le tableau de bord

Les vérifications apparaissent dans Plateforme › Vérifications, avec le numéro masqué, la clé qui les a demandées, le statut, le nombre de tentatives et, le cas échéant, la cause d'un envoi refusé ou non confirmé. Le code n'y figure jamais.

Sécurité

  • Le code est tiré d'un générateur cryptographique et n'est jamais stocké : MailPulse n'en garde qu'une empreinte HMAC salée, comparée en temps constant.
  • Un code expire après 10 minutes, supporte 5 tentatives et ne valide qu'une fois.
  • Le code part uniquement vers le numéro exact fourni, sans variante (pas d'ancien format à 8 chiffres).
  • Les numéros sont masqués dans les réponses et dans le tableau de bord. En cas d'échec d'envoi, seule une cause classée est conservée (numéro sans compte WhatsApp, délai dépassé ou erreur du fournisseur), jamais le texte du fournisseur.
  • Un refus signalé après coup ne défait jamais un code déjà validé.

Limites de WhatsApp Cloud API

Hors de la fenêtre de 24 heures ouverte par un message de l'utilisateur, Meta accepte un message libre puis ne le remet jamais. Un code de vérification doit alors passer par un modèle d'authentification approuvé, que les vérifications ne prennent pas encore en charge. Tant que c'est le cas, une organisation sur WhatsApp Cloud API reçoit 409 whatsapp_indisponible plutôt qu'un code qui n'arriverait pas.

On this page