Watch-IP

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

email
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.csv

Ré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.csv

Vé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