Référence de l'API de vérification d'e-mail
POST/v1/email/validate
Vérifie une adresse e-mail : syntaxe, domaines jetables/temporaires connus, serveur de messagerie (MX) du domaine, fautes de frappe probables et adresses génériques, puis renvoie un verdict accept/review/reject accompagné des motifs. Envoyez un corps JSON { "email": "user@example.com" }. Conçu pour être appelé depuis le JavaScript de votre formulaire d'inscription, avec le même modèle de clé publiable restreinte par origine que GET /v1/geo. Pour de nombreuses adresses ou une décision d'inscription côté serveur, utilisez les points de terminaison par lot, de tâches de liste et de vérification d'inscription décrits plus bas. Toutes les vérifications portent sur le domaine et l'adresse : aucune boîte aux lettres n'est contactée, donc aucun résultat n'établit qu'une boîte existe, à qui elle appartient, ni que le courrier y parviendra.
Authentification
POST /v1/email/validate accepte une clé publiable restreinte par origine via l'en-tête X-Api-Key — le même type de clé et le même modèle d'origines autorisées que GET /v1/geo. Tous les autres points de terminaison de cette page (lot, tâches de liste, vérification d'inscription) acceptent de nombreuses adresses ou une IP arbitraire : ils exigent donc votre clé secrète via Authorization: Bearer et ne doivent être appelés que depuis votre backend ; une clé publiable y reçoit une 403.
Champs de la réponse
- L'adresse envoyée, renvoyée exactement telle que soumise.
- domain
- Le domaine en minuscules (domaines internationalisés en punycode), ou null lorsque syntaxValid vaut false.
- syntaxValid
- Indique si l'adresse est syntaxiquement valide. Ce n'est pas une vérification d'existence de la boîte aux lettres ni de délivrabilité.
- isDisposable
- Indique si le domaine correspond à un fournisseur d'e-mails jetables/temporaires connu — directement, via un domaine parent, ou via un serveur de messagerie connu pour desservir des domaines jetables. Toujours false lorsque syntaxValid vaut false.
- normalizedEmail
- Adresse nettoyée et en minuscules, domaine en punycode, ou null lorsque syntaxValid vaut false.
- canonicalEmail
- normalizedEmail sans éventuel +tag (et, pour Gmail, sans les points, googlemail.com étant ramené à gmail.com) — conservez-le pour repérer une même personne qui s'inscrit deux fois. Null lorsque syntaxValid vaut false.
- disposableSource
- Pourquoi isDisposable vaut true : list (le domaine lui-même est listé), parent_domain (un domaine parent est listé, p. ex. a.b.mailinator.com) ou mx_host (le serveur de messagerie du domaine dessert des domaines jetables connus). Null lorsque isDisposable vaut false.
- isFreeProvider
- Indique si le domaine est un fournisseur de messagerie grand public comme gmail.com ou outlook.com. À titre informatif uniquement — ne modifie jamais le verdict.
- isRoleAccount
- Indique si la partie locale est une adresse générique comme admin@, info@ ou noreply@.
- didYouMean
- Une correction probable de faute de frappe portant sur l'adresse entière (john@gmial.com → john@gmail.com), ou null. Un domaine disposant de son propre serveur de messagerie fonctionnel n'est pas « corrigé », sauf s'il est à une modification près d'un fournisseur courant.
- mx.status
- found (des enregistrements MX existent), implicit (pas de MX, mais un enregistrement A/AAAA), none (ni l'un ni l'autre), null_mx (le domaine déclare n'accepter aucun courrier), no_domain (le domaine n'existe pas) ou unknown (la recherche a échoué ou expiré). L'objet mx entier vaut null lorsque syntaxValid vaut false.
- mx.host
- L'hôte MX de plus basse préférence lorsque status vaut found, sinon null. N'indique rien sur l'existence de la boîte aux lettres individuelle.
- verdict
- accept, review ou reject — la plus sévère des conditions présentes dans reasons. Une recommandation pour votre propre politique, pas une décision finale.
- reasons
- Chaque condition rencontrée, de la plus sévère à la moins sévère ; vide lorsque verdict vaut accept. Voir « Verdicts et codes de motif » ci-dessous.
Erreurs
- 400
- Corps de requête mal formé. Lot : empty_batch ou batch_too_large (plus de 100 adresses). Vérification d'inscription : invalid_ip. Tâches de liste : invalid_body, empty_job ou job_too_large (plus de 100 000 adresses). Une adresse e-mail invalide ne produit jamais une 400 — c'est un résultat avec le verdict reject et le motif invalid_syntax.
- 401
- Clé API manquante ou invalide.
- 403
- POST /v1/email/validate : l'Origin/Referer de la requête ne figure pas dans la liste des origines autorisées de la clé (aucun en-tête CORS n'est défini, le navigateur bloque donc la réponse quel que soit le corps JSON). Points de terminaison à clé secrète : une clé publiable a été utilisée.
- 404
- job_not_found — aucune tâche de liste avec cet identifiant pour votre compte.
- 409
- job_not_completed — la tâche est encore en file d'attente ou en cours, ou elle a échoué ; les résultats ne sont téléchargeables qu'une fois la tâche terminée.
- 410
- job_expired — les adresses envoyées et les résultats de la tâche ont été supprimés (7 jours après sa création).
- 413
- body_too_large — un envoi CSV de tâche de plus de 10 Mo.
- 415
- Un corps de tâche de liste qui n'est ni du JSON ni du text/csv.
- 429
- La limite de débit par minute, ou monthly_limit_exceeded lorsque le plafond mensuel de requêtes du forfait serait dépassé — voir erreurs et limites de débit pour les distinguer. Un lot ou une tâche de liste qui dépasserait le plafond est refusé en entier, avant tout traitement.
- 503
- job_storage_unavailable — une tâche de liste n'a pas pu être stockée. Rien n'a été facturé ; réessayez.
Exemple
Requête
curl https://api.watch-ip.com/v1/email/validate \
-H "X-Api-Key: YOUR_PUBLISHABLE_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "John.Doe+news@Gmial.com"}'Réponse
{
"email": "John.Doe+news@Gmial.com",
"domain": "gmial.com",
"syntaxValid": true,
"isDisposable": false,
"normalizedEmail": "john.doe+news@gmial.com",
"canonicalEmail": "john.doe@gmial.com",
"disposableSource": null,
"isFreeProvider": false,
"isRoleAccount": false,
"didYouMean": "john.doe+news@gmail.com",
"mx": {
"status": "none",
"host": null
},
"verdict": "reject",
"reasons": [
"no_mail_server",
"typo_suspected"
]
}Verdicts et codes de motif
Chaque condition impose un verdict minimal ; la plus sévère l'emporte, et reasons les énumère toutes, de la plus sévère à la moins sévère. L'acceptabilité d'une adresse chez un fournisseur gratuit est laissée à votre appréciation — elle ne modifie jamais le verdict.
- invalid_syntax
- Reject. L'adresse n'est pas syntaxiquement valide (limites de longueur, caractères autorisés, position des points, véritable domaine plutôt qu'une IP littérale). Les parties locales entre guillemets sont aussi refusées — légales mais pratiquement jamais utilisées à l'inscription.
- domain_not_found
- Reject. Le domaine n'existe pas dans le DNS.
- no_mail_server
- Reject. Le domaine déclare n'accepter aucun courrier (un « null MX »), ou n'a ni enregistrement MX ni enregistrement A/AAAA.
- disposable_domain
- Reject. Le domaine, un domaine parent ou le serveur de messagerie du domaine correspond à des fournisseurs d'e-mails jetables/temporaires connus — voir disposableSource.
- typo_suspected
- Review. didYouMean contient une correction probable, par exemple gmial.com → gmail.com.
- role_account
- Review. La partie locale est une adresse générique comme admin@, info@, support@ ou noreply@, généralement partagée plutôt que personnelle.
- implicit_mx
- Review. Le domaine n'a pas d'enregistrement MX ; le courrier se rabattrait sur son adresse A/AAAA, ce qui est rare pour de vrais domaines de messagerie.
- dns_unavailable
- Review. La recherche DNS a échoué ou expiré : la configuration de messagerie du domaine est inconnue (mx.status : unknown). Ce n'est pas un élément à charge contre l'adresse.
Vérification par lot
POST/v1/email/batch
Vérifie de 1 à 100 adresses en une seule requête, avec les mêmes contrôles et la même forme de résultat que POST /v1/email/validate, un résultat par adresse dans l'ordre d'envoi. Envoyez { "emails": [...] }. Les adresses d'un même domaine partagent une seule recherche DNS. Compte une requête par adresse sur le plafond mensuel de votre forfait ; un lot qui dépasserait le plafond est refusé en entier avec 429 monthly_limit_exceeded. Pour la limite de débit par minute, l'appel entier compte pour une seule requête. Clé secrète uniquement.
Requête
curl https://api.watch-ip.com/v1/email/batch \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"emails": ["user@gmail.com", "someone@mailinator.com"]}'Réponse
{
"results": [
{ "email": "user@gmail.com", "verdict": "accept", "reasons": [], ... },
{ "email": "someone@mailinator.com", "isDisposable": true, "disposableSource": "list", "verdict": "reject", "reasons": ["disposable_domain"], ... }
]
}Tâches de liste d'e-mails
POST/v1/email/jobs
Vérifie jusqu'à 100 000 adresses en arrière-plan. Envoyez du JSON { "emails": [...], "filename": "..." } ou un corps text/csv de 10 Mo au maximum : la colonne intitulée email (ou e-mail, email address, email_address ou mail, sans distinction de casse) est utilisée, ou la première colonne si aucun en-tête ne la nomme ; les séparateurs virgule, point-virgule et tabulation sont détectés. La tâche est facturée à sa création — une requête par adresse distincte (correspondance exacte), les doublons sont donc vérifiés mais facturés une seule fois — et une liste qui dépasserait votre plafond mensuel est refusée en entier. Si une partie de la tâche ne peut pas être traitée après plusieurs tentatives, la tâche est marquée failed et les crédits de la partie non traitée sont restitués. Répond 202 avec l'objet tâche. Clé secrète uniquement ; les mêmes tâches peuvent aussi être envoyées et téléchargées depuis la page Email lists du tableau de bord.
Requête
curl https://api.watch-ip.com/v1/email/jobs \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: text/csv" \
--data-binary @newsletter.csvRéponse
{
"id": "5b0d6f5e-8a51-4f7e-9d0e-2c1f3f7f8a11",
"status": "queued",
"source": "api",
"filename": null,
"total": 12840,
"credits": 12512,
"processed": 0,
"summary": null,
"createdAt": "2026-09-28T10:00:00.000Z",
"completedAt": null,
"expiresAt": "2026-10-05T10:00:00.000Z"
}Statut d'une tâche
GET/v1/email/jobs/{id}
Renvoie le même objet tâche. Interrogez-le jusqu'à ce que status vaille completed ; ces interrogations ne sont pas facturées.
- status
- queued → processing → completed. failed : une partie de la liste n'a pas pu être traitée après plusieurs tentatives ; aucun résultat n'est disponible et les crédits de la partie non traitée ont été restitués. expired : les adresses envoyées et les résultats ont été supprimés 7 jours après la création.
- total
- Lignes envoyées, doublons compris.
- credits
- Requêtes facturées : une par adresse distincte.
- processed
- Lignes vérifiées jusqu'à présent.
- summary
- Une fois terminée : nombre de lignes par verdict (accept/review/reject) et par code de motif rencontré. Null auparavant.
- expiresAt
- Date de suppression des adresses envoyées et des résultats.
Résultats d'une tâche
GET/v1/email/jobs/{id}/results
Télécharge un CSV avec une ligne par ligne envoyée, dans l'ordre d'envoi — doublons compris. Colonnes : email, normalized_email, verdict, reasons, syntax_valid, is_disposable, disposable_source, is_free_provider, is_role_account, did_you_mean, mx_status, mx_host. reasons est séparé par des points-virgules, une cellule vide signifie null, et mx_status est vide pour les adresses syntaxiquement invalides (aucune recherche n'a été faite). Une adresse invalide commençant par =, +, - ou @ est préfixée d'une apostrophe afin que les tableurs ne l'exécutent pas comme une formule. 409 tant que la tâche n'est pas terminée, 410 une fois expirée. Le téléchargement n'est pas facturé.
Requête
curl https://api.watch-ip.com/v1/email/jobs/5b0d6f5e-8a51-4f7e-9d0e-2c1f3f7f8a11/results \
-H "Authorization: Bearer YOUR_SECRET_KEY" -o results.csvVérification d'inscription
POST/v1/signup/check
Évalue une inscription à partir de son adresse e-mail et de son IP en un seul appel, depuis votre backend lors de la soumission du formulaire (un verdict calculé dans le navigateur peut être falsifié). Envoyez { "email": "...", "ip": "...", "userAgent": "..." } — userAgent est facultatif. La réponse contient le résultat complet de la vérification d'e-mail (email), le pays et l'ASN de l'IP et — sur les forfaits incluant les données de sécurité — ses indicateurs VPN/Tor/centre de données/menace (ip), l'âge du domaine de l'e-mail en jours d'après les données publiques d'enregistrement (RDAP) (emailDomainAgeDays, null s'il est inconnu et pour les grands fournisseurs grand public), un score de 0 à 100 (la somme des poids des motifs ci-dessous, plafonnée à 100) et un verdict : reject à partir de 60, review à partir de 25, sinon accept. Sur un forfait sans données de sécurité, ip.security vaut null, le score n'utilise que les signaux e-mail et reasons inclut ip_security_unavailable. Compte comme une requête. Clé secrète uniquement.
- invalid_syntax
- 70
- domain_not_found · no_mail_server · disposable_domain
- 60 chacun
- ip_tor · ip_threat
- 40 chacun
- ip_vpn
- 25
- new_domain
- 25 — le domaine de l'e-mail a été enregistré il y a moins de 30 jours
- ip_datacenter
- 20 — uniquement si l'IP n'est pas déjà une sortie VPN ou Tor
- automated_user_agent
- 20 — le userAgent fourni ressemble à un bot ou à un script
- typo_suspected
- 15
- role_account · implicit_mx
- 10 chacun
- dns_unavailable
- 5
- ip_security_unavailable
- 0 — informatif : ce forfait n'inclut pas de données de sécurité
Requête
curl https://api.watch-ip.com/v1/signup/check \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "jane@new-startup.io", "ip": "203.0.113.1"}'Réponse
{
"email": { "email": "jane@new-startup.io", "verdict": "accept", "reasons": [], ... },
"ip": {
"ip": "203.0.113.1",
"country": "US",
"asn": 64500,
"asOrganization": "Example Hosting",
"security": { "isTor": false, "isVpn": false, "isDatacenter": true, "isThreat": false, "isSanctionedNetwork": false }
},
"emailDomainAgeDays": 12,
"score": 45,
"verdict": "review",
"reasons": ["new_domain", "ip_datacenter"]
}Limites
Chaque adresse vérifiée compte comme une requête sur le plafond mensuel partagé de votre forfait — une vérification unitaire, chaque adresse d'un lot, chaque adresse distincte d'une tâche de liste — et une vérification d'inscription compte comme une requête. Les lots et les tâches de liste sont acceptés ou refusés en entier, jamais traités partiellement. La limite de débit par minute compte les appels HTTP, pas les éléments : un lot de jusqu'à 100 IP ou adresses e-mail compte pour une seule requête, tandis que chaque élément compte toujours séparément dans le plafond mensuel de requêtes. Les envois et résultats des tâches de liste sont supprimés 7 jours après la création de la tâche. Les recherches DNS disposent d'un court délai : en cas d'échec ou d'expiration, le résultat se dégrade en mx.status unknown et motif dns_unavailable plutôt qu'en erreur. Les données de domaines jetables proviennent de la fusion de trois listes open source maintenues par la communauté, actualisées toutes les quelques heures et complétées par les serveurs de messagerie observés desservant des domaines listés — voir sources de données. Un fournisseur jetable très récent peut ne pas encore être signalé. Toutes les vérifications portent sur le domaine et l'adresse : aucune boîte aux lettres n'est contactée, donc aucun résultat n'établit qu'une boîte existe, à qui elle appartient, ni que le courrier y parviendra.
Pages associées
- AuthentificationClés publiables ou secrètes, restriction par origine et limites de débit.
- Référence de GET /v1/geoRéférence complète des champs pour le point de terminaison de géolocalisation du visiteur.
- Détection d'e-mails jetablesSignalez les e-mails d'inscription jetables, mal saisis ou sans serveur de messagerie, un par un ou en masse.
- Prévention des abus d'inscriptionCombinez les signaux de l'e-mail et de l'IP pour décider d'accepter, d'examiner ou de refuser une inscription.
- Sources de donnéesQuelle source alimente chaque champ de réponse, et ses lacunes connues.