# VaEmail, documentation complète Toutes les pages de https://vaemail.fr rassemblées, dans l'ordre d'une prise en main. Générée par `php artisan docs:generer`. ============================================================================== # Source : https://vaemail.fr/llms.txt ============================================================================== # VaEmail > Infrastructure email pour applications et agents IA autonomes. Envoi transactionnel et > campagnes, authentification des domaines, suivi de remise message par message, > diagnostic de délivrabilité. Serveurs en Allemagne, envoi via Amazon SES Europe. VaEmail expose 63 endpoints REST, un serveur MCP, une interface en ligne de commande et une API compatible Brevo. Le produit est conçu pour être piloté par un programme : erreurs structurées avec code stable et action corrective, requêtes idempotentes, essai à blanc avant envoi, clés d'API bornées en portée et en volume, journal de chaque action. ## Pour quels usages - donner à un agent IA la capacité d'envoyer un email - email transactionnel déclenché par une application - campagnes email et séquences de prospection - authentification de domaine (SPF, DKIM, DMARC) et diagnostic de délivrabilité - remplacer Brevo sans réécrire le code appelant - infrastructure email hébergée en Europe ## Interfaces - API REST : https://app.vaemail.fr/api/v1 - Serveur MCP et ligne de commande : `npx -y vaemail mcp` (paquet npm `vaemail`, aucune dépendance) - API compatible Brevo : https://app.vaemail.fr/v3 - SMTP et webhooks ## Documentation - [Page agents](https://vaemail.fr/agents) : installation et garde-fous, en une page - [Démarrage](https://vaemail.fr/docs/quickstart.md) : du compte au premier email remis - [Référence de l'API](https://vaemail.fr/docs/api.md) : tous les endpoints - [Codes d'erreur](https://vaemail.fr/docs/errors.md) : chaque code, ce qu'il veut dire, quoi faire - [Serveur MCP](https://vaemail.fr/docs/mcp.md) : les 13 outils et leur usage - [Domaines](https://vaemail.fr/docs/domains.md) : authentifier un domaine d'envoi - [Délivrabilité](https://vaemail.fr/docs/deliverability.md) : pourquoi le courrier arrive mal - [Sécurité](https://vaemail.fr/docs/security.md) : portées, plafonds, journal, données - [Spécification OpenAPI 3.1](https://app.vaemail.fr/openapi.json) - [Capacités du service](https://app.vaemail.fr/api/v1/capabilities), sans authentification - [Documentation complète en un fichier](https://vaemail.fr/llms-full.txt) - [Skill d'agent](https://vaemail.fr/skill) : les règles d'usage, à installer avec `npx skills add vaemail/skills` - [Comparatif](https://vaemail.fr/compare/index.md) : VaEmail face à Resend, Brevo, Postmark et AgentMail, sources citées ## À savoir avant d'appeler - Un envoi rend 202 : le message est ACCEPTÉ, pas remis. La remise se lit sur `GET /api/v1/messages/{id}`. Ne pas annoncer une remise sur la foi du 202. - Une relance après un délai réseau doit porter l'en-tête `Idempotency-Key`, sinon le message part deux fois. - Avant le premier envoi réel, `POST /api/v1/messages/validate` dit si l'envoi passerait, sans rien envoyer. - `POST /v3/emailCampaigns/{id}/sendNow` est irréversible : l'envoi part à toute une liste. Exige une validation humaine explicite. - Publier des enregistrements DNS et ouvrir un compte sont des étapes humaines. Un enregistrement marqué `publishable: false` contient encore une valeur à obtenir : le poser tel quel casserait l'authentification du domaine. - VaEmail n'a pas de boîte de réception générique : on ne peut pas créer une adresse à la volée pour recevoir un code de vérification. ============================================================================== # Source : https://vaemail.fr/docs/quickstart.md ============================================================================== # Démarrage Du compte au premier email remis. Comptez cinq minutes, plus le temps de propagation DNS, qui ne dépend pas de nous. ## 1. Une clé d'API Elle se crée depuis le tableau de bord VaEmail, rubrique « Clés API ». C'est une étape humaine : il n'y a pas d'endpoint de création de compte, et un agent ne peut pas s'en procurer une tout seul. Une clé destinée à un agent gagne à être bornée dès sa création : portées limitées à ce dont il a besoin, plafond d'envois par jour, et liste des domaines expéditeurs autorisés. Voir [Sécurité](https://vaemail.fr/docs/security.md). ``` export VAEMAIL_API_KEY=swm_votre_cle ``` ## 2. Vérifier que tout répond ``` npx vaemail init ``` La commande dit, dans l'ordre : si le service répond, si la clé est acceptée, et si un domaine d'envoi est authentifié. Elle affiche aussi la configuration MCP à coller. Sans installer quoi que ce soit : ``` curl https://app.vaemail.fr/api/v1/capabilities ``` Cet appel ne demande pas de clé. Il décrit ce que le service sait faire, ses limites et ses portées. ## 3. Déclarer un domaine d'envoi Envoyer depuis un domaine non authentifié, c'est envoyer dans les indésirables. Les grands fournisseurs de messagerie vérifient SPF et DMARC avant de décider où poser le message. ``` npx vaemail domains:add exemple.fr ``` La réponse contient les enregistrements DNS à publier, avec le rôle de chacun. Un enregistrement marqué `publishable: false` contient encore une valeur qui dépend de la configuration du serveur d'envoi : la publier telle quelle casserait l'authentification. Demandez-la avant de poser cet enregistrement. Publier les enregistrements se fait chez votre registrar. C'est une étape humaine. Une fois publiés, comptez de quelques minutes à quelques heures, puis : ``` npx vaemail domains ``` ## 4. Un essai à blanc Avant le premier vrai message : ``` curl -X POST https://app.vaemail.fr/api/v1/messages/validate \ -H "api-key: $VAEMAIL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"to":"client@exemple.fr","html":"
Bonjour
"}' ``` La réponse dit si l'envoi passerait (`sendable`) et, sinon, ce qui le bloque, avec les mêmes codes que les erreurs d'envoi. Rien n'est envoyé. ## 5. Envoyer ``` curl -X POST https://app.vaemail.fr/api/v1/transactional/send \ -H "api-key: $VAEMAIL_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: facture-2412" \ -d '{"to":"client@exemple.fr","subject":"Votre facture","html":"Bonjour
"}' ``` Réponse : ```json { "success": true, "data": { "id": 2841, "status": "queued" } } ``` Le 202 dit que le message est accepté et mis en file. Il ne dit pas qu'il est arrivé. L'en-tête `Idempotency-Key` est facultatif mais fortement recommandé dès qu'un programme appelle : si la réponse se perd et que l'appel est relancé, la première réponse est rejouée au lieu d'envoyer un deuxième message. ## 6. Savoir ce qu'il est devenu ``` curl https://app.vaemail.fr/api/v1/messages/2841 \ -H "api-key: $VAEMAIL_API_KEY" ``` `status` passe par `queued`, puis `sent`, puis `delivered` quand le fournisseur du destinataire confirme la remise. En cas d'échec, `error` porte le motif renvoyé par le transport, et `events` la suite de ce qui s'est passé. C'est ce seul appel qui autorise à dire qu'un email est arrivé. ## Ensuite - [Serveur MCP](https://vaemail.fr/docs/mcp.md), pour brancher un agent conversationnel - [Référence de l'API](https://vaemail.fr/docs/api.md), tous les endpoints - [Codes d'erreur](https://vaemail.fr/docs/errors.md), et quoi faire pour chacun - [Délivrabilité](https://vaemail.fr/docs/deliverability.md), quand le courrier arrive mal ============================================================================== # Source : https://vaemail.fr/docs/agents.md ============================================================================== # Brancher VaEmail à un agent Cette page s'adresse à un agent de code (Claude Code, Codex, Cursor, un agent MCP) ou à la personne qui le pilote. Elle dit ce qu'un agent peut faire seul, ce qui reste une étape humaine, et dans quel ordre s'y prendre. ## À copier dans votre agent de code ``` Intègre VaEmail à ce projet comme fournisseur d'email sortant. Documentation officielle pour agents : https://vaemail.fr/llms.txt Spécification OpenAPI : https://app.vaemail.fr/openapi.json Ce que le service sait faire, sans clé : https://app.vaemail.fr/api/v1/capabilities Règles : - La clé d'API est dans la variable d'environnement VAEMAIL_API_KEY. Ne la demande pas, ne l'écris jamais dans un fichier versionné. - Avant tout envoi réel, appelle POST /api/v1/messages/validate et arrête-toi si « sendable » vaut false. - Mets un en-tête Idempotency-Key sur chaque envoi, dérivé de l'action métier. - Un 202 signifie « accepté », pas « remis » : lis GET /api/v1/messages/{id} avant d'annoncer une remise. - Publier des enregistrements DNS, créer un compte ou payer sont des étapes humaines : signale-les, ne les déclare jamais faites. ``` ## Ce qu'un agent peut faire seul | Étape | Comment | | --- | --- | | Découvrir le service | `GET /api/v1/capabilities`, sans clé | | Vérifier sa clé et l'état du compte | `npx vaemail init` ou `GET /api/v1/usage` | | Déclarer un domaine d'envoi | `POST /api/v1/domains` | | Obtenir les enregistrements DNS à publier | `GET /api/v1/domains/{domaine}/dns` | | Vérifier qu'un domaine est authentifié | `POST /api/v1/domains/verify` | | Savoir si un envoi passerait | `POST /api/v1/messages/validate` | | Envoyer | `POST /api/v1/transactional/send` avec `Idempotency-Key` | | Suivre la remise | `GET /api/v1/messages/{id}` | | Comprendre une erreur | le bloc `error` : `code`, `resolution`, `retryable`, `documentation` | | Diagnostiquer une mauvaise délivrabilité | `GET /api/v1/deliverability/diagnose?domain=` | | Savoir ce qu'il lui reste | `GET /api/v1/usage` | | Rendre compte de ce qu'il a fait | `GET /api/v1/audit-logs` | Les treize outils du [serveur MCP](https://vaemail.fr/docs/mcp.md) couvrent les mêmes étapes. ## Ce qui reste humain - **Créer le compte et la clé d'API.** Il n'y a pas d'endpoint d'inscription. La clé se crée depuis le tableau de bord, et c'est là qu'on la borne (voir ci-dessous). - **Publier les enregistrements DNS** chez le registrar. L'API rend les valeurs, pas l'accès à la zone. Un enregistrement marqué `publishable: false` attend encore une valeur : le poser tel quel casserait l'authentification. - **Payer** un abonnement ou relever un quota. - **Expédier une campagne à toute une liste.** `POST /v3/emailCampaigns/{id}/sendNow` exige une confirmation explicite dans le corps de la requête : il ne se lance pas par accident. ## Une clé pour un agent Créer une clé dédiée, nommée d'après l'agent, et la borner à la création : - portées : `email.send` et `email.read_status` suffisent pour envoyer et suivre ; ajouter `domain.read` et `domain.write` si l'agent configure le domaine ; - `max_emails_per_day` : le volume que l'agent est censé produire, pas plus ; - `max_recipients_per_email` : 1 pour du transactionnel ; - `allowed_domains` : le seul domaine expéditeur prévu. Le [journal](https://vaemail.fr/docs/security.md#journal) rend ensuite lisible tout ce que cette clé a fait, et la révoquer n'arrête rien d'autre. ## Ce que VaEmail ne fait pas - Pas de boîte de réception créée à la volée : un agent ne peut pas obtenir une adresse pour recevoir un code de vérification ou une réponse. La réception existe pour les séquences de prospection (`/v3/outreach/inbox`), rattachée à une boîte IMAP déclarée. - Pas de coût par message dans l'API : les plafonds se posent en nombre d'emails, pas en euros. - Pas d'inscription par API. ## Où sont les choses - Index pour les modèles de langage : https://vaemail.fr/llms.txt - Toute la documentation en un fichier : https://vaemail.fr/llms-full.txt - Spécification OpenAPI 3.1 : https://app.vaemail.fr/openapi.json - Capacités du service : https://app.vaemail.fr/api/v1/capabilities - Codes d'erreur : https://vaemail.fr/docs/errors.md - Serveur MCP et ligne de commande : https://vaemail.fr/docs/mcp.md ============================================================================== # Source : https://vaemail.fr/docs/mcp.md ============================================================================== # Serveur MCP Le serveur MCP donne à un agent conversationnel treize outils pour piloter VaEmail. Il n'a aucune dépendance : Node 18 et rien d'autre. Un paquet qu'un agent installe seul ne devrait pas tirer un arbre de dépendances derrière lui, et devrait pouvoir se lire en entier avant qu'on lui confie une clé d'API. ## Installation Avec Claude Code : ``` claude mcp add vaemail --env VAEMAIL_API_KEY=swm_votre_cle -- npx -y vaemail mcp ``` Avec n'importe quel client MCP : ```json { "mcpServers": { "vaemail": { "command": "npx", "args": ["-y", "vaemail", "mcp"], "env": { "VAEMAIL_API_KEY": "swm_votre_cle" } } } } ``` Variables lues : `VAEMAIL_API_KEY`, et `VAEMAIL_BASE_URL` pour pointer ailleurs que la production. ## Les outils | Outil | Ce qu'il fait | | --- | --- | | `vaemail_capabilities` | Ce que le service sait faire. Sans clé. | | `vaemail_send_email` | Met un email en file, rend son identifiant. | | `vaemail_validate_email` | Essai à blanc : dit si l'envoi passerait. N'envoie rien. | | `vaemail_get_message` | Statut de remise et événements d'un message. | | `vaemail_list_messages` | Messages récents, filtrés. | | `vaemail_list_domains` | Domaines d'envoi et état de leur authentification. | | `vaemail_create_domain` | Déclare un domaine, rend les enregistrements DNS. | | `vaemail_verify_domain` | Relit le DNS et dit ce qui est authentifié. | | `vaemail_dns_requirements` | Ce qui manque à un domaine déclaré. | | `vaemail_diagnose_deliverability` | Pourquoi le courrier arrive mal, et quoi faire. | | `vaemail_list_bounces` | Adresses sorties du circuit, et pourquoi. | | `vaemail_get_usage` | Quota, plafond de la clé, ce qu'il reste. | | `vaemail_get_audit_log` | Ce que cette clé a fait. | Les outils de lecture portent l'annotation `readOnlyHint`, ce qui permet à un agent de savoir lesquels il peut appeler sans demander la permission. ## Ce que le serveur dit à l'agent Les instructions renvoyées à l'initialisation tiennent en quatre phrases, et elles comptent autant que les outils : - un envoi est accepté, pas remis ; l'issue se lit sur `vaemail_get_message` ; - avant le premier envoi réel, passer par `vaemail_validate_email` ; - quand le courrier arrive mal, appeler `vaemail_diagnose_deliverability` plutôt que de supposer ; - publier des enregistrements DNS et payer un abonnement sont des étapes humaines : les signaler, jamais les déclarer faites. ## Erreurs Une erreur de l'API ne remonte pas comme un échec de transport, mais comme un résultat d'outil marqué en erreur, avec le code, l'action corrective et la mention de ce qui peut être retenté. L'agent voit le motif et peut corriger, au lieu de recevoir un échec opaque. Exemple de ce que reçoit l'agent : ``` RECIPIENT_SUPPRESSED: Destinataire dans la liste de suppression. Action corrective : remove_from_suppression_list (/v3/smtp/blockedContacts) Réessayer à l'identique ne changera rien. ``` ## Ligne de commande Le même paquet fournit `vaemail`, utile pour vérifier une configuration ou pour un agent qui exécute des commandes plutôt que d'appeler des outils. ``` vaemail init vaemail doctor vaemail send --to client@exemple.fr --subject Bonjour --html 'Salut
' vaemail status 2841 ``` `--json` sur n'importe quelle commande donne une sortie exploitable par un programme. ============================================================================== # Source : https://vaemail.fr/docs/domains.md ============================================================================== # Authentifier un domaine d'envoi Un email envoyé depuis un domaine sans SPF ni DMARC finit dans les indésirables, quel que soit son contenu. C'est le premier point à régler, avant d'écrire quoi que ce soit. ## Déclarer ``` POST /api/v1/domains { "domain": "exemple.fr" } ``` La réponse contient l'état actuel de l'authentification et les enregistrements à publier : ```json { "domain": "exemple.fr", "authentication": { "spf": {...}, "dkim": {...}, "dmarc": {...}, "ok": false }, "dns_records": [ { "type": "TXT", "host": "@", "value": "v=spf1 ...", "role": "SPF, autorise notre serveur à envoyer pour ce domaine.", "publishable": true, "missing_values": [] } ], "dns_ready": true, "dns_note": null, "next_step": "Poser les enregistrements DNS, puis rappeler POST /api/v1/domains/verify." } ``` L'appel est idempotent : redéclarer le même domaine ne crée pas de doublon et renvoie son état. ## Le champ `publishable` Certaines valeurs dépendent de la configuration du serveur d'envoi et ne sont pas connues au moment de la réponse. L'enregistrement porte alors `publishable: false` et `missing_values` nomme ce qui manque. Publier un enregistrement dans cet état casserait l'authentification du domaine, sans message d'erreur nulle part : le domaine paraîtrait configuré et les emails partiraient mal. Un agent doit signaler ces valeurs et attendre, pas les publier. `dns_ready` résume : vrai quand tous les enregistrements sont publiables en l'état. ## Publier, puis vérifier Publier se fait chez le registrar du domaine. C'est une étape humaine. Ensuite : ``` POST /api/v1/domains/verify { "domain": "exemple.fr" } ``` La vérification lit le DNS public en direct, elle ne consulte pas un état enregistré chez nous. Comptez de quelques minutes à quelques heures de propagation. ## Les trois enregistrements - **SPF** dit quels serveurs ont le droit d'envoyer pour le domaine. Sans lui, un fournisseur ne peut pas distinguer votre envoi d'une usurpation. - **DKIM** signe chaque message. La signature survit au transit, ce qui prouve que le message n'a pas été modifié en route. - **DMARC** dit au fournisseur quoi faire quand SPF et DKIM échouent, et où envoyer les rapports. Commencer en `p=none` : on observe avant de durcir. `ok` vaut vrai dès que SPF et DMARC sont présents. DKIM dépend du sélecteur, et n'est vérifié que si un sélecteur a été déclaré. ============================================================================== # Source : https://vaemail.fr/docs/deliverability.md ============================================================================== # Pourquoi le courrier arrive mal Un seul appel répond à la question, avec les constats et les actions qui les corrigent : ``` GET /api/v1/deliverability/diagnose ``` En MCP : `vaemail_diagnose_deliverability`. En ligne de commande : `vaemail doctor`. ## Ce que rend le diagnostic - `status` : `ok`, `warning` ou `critical`. Un verdict lisible sans interpréter le détail. - `authentication` : pour chaque domaine déclaré, l'état réel de SPF, DKIM et DMARC, lu dans le DNS public au moment de l'appel. - `issues` : les constats de réputation, du plus grave au moins grave, avec leur cause en clair et les actions disponibles. - `recommended_actions` : ce qu'il faut faire, avec l'endpoint qui le réalise. - `by_domain` : les taux de remise par domaine destinataire, utile pour repérer un fournisseur qui filtre. ## Les deux causes les plus fréquentes **Le domaine n'est pas authentifié.** C'est visible dans `authentication`, et c'est toujours la première chose à regarder. Voir [Domaines](https://vaemail.fr/docs/domains.md). **La liste est usée.** Des adresses qui n'existent plus font monter le taux de rebonds durs, et un taux élevé abîme la réputation du domaine pour tous les envois suivants, y compris transactionnels. Le diagnostic distingue deux choses qu'on confond souvent : - un **rebond dur** est de l'usure de liste. L'adresse n'existe plus. Elle est déjà bloquée et ne repartira pas, mais tant qu'elle reste dans les listes, chaque nouvel import la remet en circulation. - une **plainte** met en cause le contenu ou la provenance des contacts. C'est le signal le plus lourd pour un fournisseur de messagerie. Il faut comprendre d'où viennent ces contacts avant de renvoyer. ## Les adresses sorties du circuit ``` GET /api/v1/suppressions ``` Toute adresse listée là est refusée à l'envoi. Un programme qui ne lit pas cette liste réessaie indéfiniment une adresse morte et fait monter son propre taux de rebonds. Raisons possibles : `hard_bounce`, `soft_bounce_limit`, `complaint`, `unsubscribe`, `manual`. ## Avant d'envoyer `POST /api/v1/messages/validate` dit si un envoi passerait, y compris le fait que le destinataire est sur la liste de suppression, sans rien envoyer ni rien consommer. ============================================================================== # Source : https://vaemail.fr/docs/security.md ============================================================================== # Sécurité et garde-fous Une personne qui se trompe s'arrête d'elle-même. Un programme qui se trompe recommence. Les garde-fous ci-dessous existent pour ça. Tous sont facultatifs : une clé qui ne déclare ni portée ni plafond n'en subit aucun, ce qui est le comportement des clés créées avant leur mise en place. ## Portées Une clé peut être restreinte à ce dont son porteur a besoin : | Portée | Ce qu'elle autorise | | --- | --- | | `email.send` | Envoyer des emails, transactionnels et campagnes. | | `email.read_status` | Lire le statut de livraison des messages. | | `domain.read` | Lire les domaines et leur authentification. | | `domain.write` | Déclarer et vérifier un domaine. | | `contacts.read` | Lire les contacts, les listes, les suppressions. | | `contacts.write` | Créer et modifier les contacts et les listes. | | `analytics.read` | Lire les statistiques, la délivrabilité, le journal. | | `billing.read` | Lire la consommation et les quotas. | Un appel hors portée reçoit un 403 avec le code `INSUFFICIENT_SCOPE`, la portée qui manque, et celles que la clé possède. Un agent peut donc dire précisément ce qui lui manque, au lieu d'échouer sans savoir pourquoi. Chaque endpoint de la [référence](https://vaemail.fr/docs/api.md) indique la portée qu'il exige, et la spécification OpenAPI la porte en `x-vaemail-scope`. ## Plafonds Par clé : - `max_emails_per_day` : plafond d'envois par jour. Au-delà, un 429 avec le code `DAILY_LIMIT_REACHED`, marqué `retryable: true` puisque le plafond se remet à zéro. - `max_recipients_per_email` : nombre de destinataires par message. - `allowed_domains` : domaines expéditeurs autorisés. Un envoi depuis un autre domaine reçoit un 403 `SENDER_DOMAIN_NOT_ALLOWED`. `GET /api/v1/usage` rend ce qui reste. Un programme qui ne sait pas combien il lui reste ne peut pas décider de s'arrêter. ## Idempotence L'en-tête `Idempotency-Key` mémorise la réponse pendant 24 heures et la rejoue à l'identique, avec `Idempotent-Replay: true`. La même clé réutilisée avec un contenu différent est refusée par un 409 `IDEMPOTENCY_KEY_REUSED` : c'est une erreur d'appel, pas un rejeu, et rejouer la première réponse donnerait un résultat qui ne correspond pas à la demande. Les erreurs serveur (5xx) ne sont pas mémorisées : elles doivent rester retentables. ## Journal `GET /api/v1/audit-logs` rend une ligne par appel : quelle clé, quel agent, quelle opération, quels paramètres, quel résultat, combien d'emails engagés. Le corps des messages, les pièces jointes et les variables de fusion n'y figurent jamais. On garde de quoi comprendre l'action, pas de quoi relire le courrier. ## Actions irréversibles `POST /v3/emailCampaigns/{id}/sendNow` expédie immédiatement à toute une liste. L'appel exige une confirmation explicite dans le corps de la requête, et la spécification le marque `x-vaemail-destructive: true`. Ce garde-fou existe parce que le 5 septembre 2026, un appel sans corps a expédié 2 982 emails un samedi soir. ## Données Serveurs en Allemagne, envoi via Amazon SES Europe. Export et effacement d'un contact par API (`/api/v1/contacts/export` et `/api/v1/contacts/erase`). L'effacement est irréversible : les données personnelles partent, l'adresse reste en liste de suppression pour ne pas être recontactée. ## Clés d'API Une clé n'est jamais stockée en clair : seule son empreinte est conservée, et elle n'est affichée qu'une fois, à la création. Elle peut porter une date d'expiration et être révoquée à tout moment. Pour un agent, créer une clé dédiée, bornée, nommée, plutôt que de réutiliser celle d'une application : le journal devient lisible, et la révoquer n'arrête rien d'autre. ============================================================================== # Source : https://vaemail.fr/docs/errors.md ============================================================================== # Codes d'erreur Générés depuis le code : `php artisan docs:generer`. Toute erreur de l'API porte un bloc `error` en plus des champs historiques `success` et `message` : ```json { "success": false, "message": "Le domaine expéditeur n'est pas dans ceux autorisés pour cette clé.", "error": { "code": "SENDER_DOMAIN_NOT_ALLOWED", "message": "Le domaine expéditeur n'est pas dans ceux autorisés pour cette clé.", "retryable": false, "resolution": { "action": "use_allowed_sender_domain" }, "documentation": "https://vaemail.fr/docs/errors#sender_domain_not_allowed" } } ``` `code` est stable : on en ajoute, on n'en renomme pas. Un programme peut brancher son comportement dessus. `retryable` dit si le même appel peut aboutir plus tard sans rien changer ; quand il vaut `false`, relancer à l'identique ne sert à rien. ## Liste des codes ### `DOMAIN_NOT_VERIFIED` Le domaine d'envoi n'est pas authentifié. ### `RECIPIENT_SUPPRESSED` Destinataire dans la liste de suppression. ### `TEMPLATE_NOT_FOUND` Template transactionnel introuvable. ### `MESSAGE_NOT_FOUND` Message introuvable. ### `CONTENT_REQUIRED` Fournir « html » ou « template_id ». ### `QUOTA_EXCEEDED` Quota mensuel atteint. ### `DAILY_LIMIT_REACHED` Plafond journalier de la clé d'API atteint. ### `TOO_MANY_RECIPIENTS` Plus de destinataires que ce que la clé autorise. ### `SENDER_DOMAIN_NOT_ALLOWED` Domaine expéditeur hors de ceux autorisés pour cette clé. ### `INSUFFICIENT_SCOPE` La clé d'API ne porte pas la portée nécessaire. ### `IDEMPOTENCY_KEY_REUSED` Clé d'idempotence déjà utilisée avec un contenu différent. ### `UNAUTHORIZED` Clé API manquante, invalide ou compte désactivé. ### `VALIDATION_FAILED` Paramètres invalides. ### `RATE_LIMITED` Trop de requêtes. ============================================================================== # Source : https://vaemail.fr/docs/api.md ============================================================================== # Référence de l'API VaEmail Générée depuis la spécification OpenAPI, elle-même dérivée des routes réellement servies. Ne pas éditer à la main : `php artisan docs:generer`. Spécification complète : https://app.vaemail.fr/openapi.json Capacités du service : https://app.vaemail.fr/api/v1/capabilities ## Authentification Toutes les routes, sauf `/api/v1/capabilities`, attendent la clé du compte en en-tête : ``` api-key: swm_votre_cle ``` `X-Api-Key` est accepté aussi, par compatibilité. ## Portées Une clé peut être restreinte à certaines portées. Une clé qui n'en déclare aucune les a toutes. | Portée | Ce qu'elle autorise | | --- | --- | | `email.send` | Envoyer des emails (transactionnel et campagnes). | | `email.read_status` | Lire le statut de livraison des messages. | | `domain.read` | Lire les domaines et leur authentification. | | `domain.write` | Déclarer et vérifier un domaine. | | `contacts.read` | Lire les contacts et les listes. | | `contacts.write` | Créer et modifier les contacts et les listes. | | `analytics.read` | Lire les statistiques et la délivrabilité. | | `billing.read` | Lire la consommation et les quotas. | ## Découverte Ce que le service sait faire, sans authentification. ### `GET /api/v1/capabilities` Ce que le service sait faire Premier appel utile : décrit le produit, ses interfaces, ses limites et ses portées, sans clé d'API. Sert à décider si VaEmail couvre un besoin avant même d'ouvrir un compte. ### `GET /api/v1/health` État du service Base de données, file d'attente et transporteur. Répond 503 si la base est injoignable. ## Transactionnel Envoi unitaire déclenché par une application ou un agent. ### `POST /api/v1/transactional/send` Envoyer un email Met un message en file et répond immédiatement 202 avec son identifiant : la réponse dit que le message est ACCEPTÉ, pas qu'il est arrivé. Pour la remise, interroger GET /api/v1/messages/{id}. Portée de clé nécessaire : `email.send`. Accepte l'en-tête `Idempotency-Key` : une relance rejoue la réponse au lieu de refaire l'action. Débit : 60 requêtes par minute. ### `POST /v3/smtp/email` Envoyer un email (schéma Brevo) Même schéma que `POST https://api.brevo.com/v3/smtp/email`. Pour un nouveau développement, préférer `/api/v1/transactional/send`, qui rend des erreurs structurées. Débit : 300 requêtes par minute. ### `GET /v3/smtp/templates` Lister les templates transactionnels Lister les templates transactionnels ## Messages Suivi de livraison et vérification avant envoi. ### `GET /api/v1/messages` Lister les messages Du plus récent au plus ancien. Pagination par curseur : rappeler l'endpoint avec `cursor` = `next_cursor`. Portée de clé nécessaire : `email.read_status`. Paramètres : - `status` : Filtre : queued, sent, delivered, failed, suppressed, held, cancelled. - `tag` : Filtre sur l'étiquette posée à l'envoi. - `to` : Filtre sur le destinataire. - `limit` : Nombre de lignes, 1 à 200 (50 par défaut). - `cursor` : Curseur de pagination renvoyé par un appel précédent. ### `POST /api/v1/messages/validate` Essai à blanc d'un envoi Dit si l'envoi passerait et nomme ce qui le bloquerait, SANS rien envoyer. À utiliser après une configuration, avant le premier vrai message. Portée de clé nécessaire : `email.send`. ### `GET /api/v1/messages/{id}` Statut d'un message Statut de remise et suite des événements connus (remise, ouverture, clic, rebond, plainte). Portée de clé nécessaire : `email.read_status`. ## Campagnes Envoi en masse à une liste, et son cycle de vie. ### `POST /api/v1/automations/abandoned-cart` Déclencher le scénario « panier abandonné » Déclencher le scénario « panier abandonné » Portée de clé nécessaire : `email.send`. ### `POST /api/v1/campaigns/conversion` Déclarer une conversion Rattache un achat ou une inscription à la campagne qui l'a précédé. ### `POST /api/v1/campaigns/preview` Prévisualiser une campagne Rend le HTML final d'une campagne, variables fusionnées, sans l'envoyer. Portée de clé nécessaire : `email.send`. ### `POST /api/v1/campaigns/send` Envoyer une campagne Déclenche l'envoi à toute une liste. Portée de clé nécessaire : `email.send`. Accepte l'en-tête `Idempotency-Key` : une relance rejoue la réponse au lieu de refaire l'action. Débit : 10 requêtes par minute. ### `GET /api/v1/campaigns/{id}/stats` Statistiques d'une campagne Statistiques d'une campagne Portée de clé nécessaire : `analytics.read`. ### `GET /v3/emailCampaigns` Lister les campagnes Lister les campagnes ### `POST /v3/emailCampaigns` Créer une campagne Créer une campagne ### `GET /v3/emailCampaigns/{id}` Lire une campagne Lire une campagne ### `PUT /v3/emailCampaigns/{id}` Modifier une campagne Modifier une campagne ### `DELETE /v3/emailCampaigns/{id}` Supprimer une campagne Supprimer une campagne ### `POST /v3/emailCampaigns/{id}/cancel` Annuler un envoi Annuler un envoi ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ### `POST /v3/emailCampaigns/{id}/pause` Interrompre un envoi en cours Interrompre un envoi en cours ### `POST /v3/emailCampaigns/{id}/resume` Reprendre un envoi interrompu Reprendre un envoi interrompu ### `POST /v3/emailCampaigns/{id}/schedule` Programmer un envoi Programmer un envoi ### `POST /v3/emailCampaigns/{id}/sendNow` Envoyer maintenant ACTION DESTRUCTIVE ET IRRÉVERSIBLE : les emails partent immédiatement à toute la liste. Exige une confirmation explicite dans le corps de la requête. Un appel sans corps a expédié 2 982 emails un samedi soir le 05/09/2026 ; la confirmation existe depuis. ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. Débit : 10 requêtes par minute. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ### `POST /v3/emailCampaigns/{id}/sendTest` Envoyer un test À faire avant tout envoi réel. Débit : 20 requêtes par minute. ### `GET /v3/emailCampaigns/{id}/statistics` Statistiques d'une campagne Statistiques d'une campagne ### `PUT /v3/emailCampaigns/{id}/status` Changer le statut d'une campagne Changer le statut d'une campagne ### `POST /v3/emailCampaigns/{id}/stop` Interrompre un envoi en cours (synonyme de pause) Interrompre un envoi en cours (synonyme de pause) ## Contacts Contacts, listes et attributs personnalisés. ### `GET /v3/contacts` Lister les contacts Lister les contacts ### `POST /v3/contacts` Créer ou mettre à jour un contact Créer ou mettre à jour un contact ### `GET /v3/contacts/attributes` Lister les attributs personnalisés Lister les attributs personnalisés ### `POST /v3/contacts/attributes/{category}/{name}` Créer un attribut Créer un attribut ### `PUT /v3/contacts/attributes/{category}/{name}` Modifier un attribut Modifier un attribut ### `DELETE /v3/contacts/attributes/{category}/{name}` Supprimer un attribut Supprimer un attribut ### `POST /v3/contacts/import` Importer des contacts en lot Importer des contacts en lot ### `GET /v3/contacts/lists` Lister les listes Lister les listes ### `POST /v3/contacts/lists` Créer une liste Créer une liste ### `GET /v3/contacts/lists/{id}` Lire une liste Lire une liste ### `PUT /v3/contacts/lists/{id}` Renommer une liste Renommer une liste ### `DELETE /v3/contacts/lists/{id}` Supprimer une liste Supprimer une liste ### `GET /v3/contacts/{identifier}` Lire un contact L'identifiant est l'adresse email ou l'identifiant numérique. ### `PUT /v3/contacts/{identifier}` Modifier un contact Modifier un contact ### `DELETE /v3/contacts/{identifier}` Supprimer un contact Supprimer un contact ## Domaines Authentification des domaines d'envoi (SPF, DKIM, DMARC). ### `GET /api/v1/domains` Lister les domaines d'envoi Chaque domaine déclaré, avec l'état réel de son SPF, DKIM et DMARC lu dans le DNS public. Portée de clé nécessaire : `domain.read`. ### `POST /api/v1/domains` Déclarer un domaine d'envoi Deuxième étape d'une installation autonome, juste après la clé. Rend les enregistrements DNS à poser et l'état courant de l'authentification : sans SPF ni DMARC, tout ce qui part est classé en indésirable. Portée de clé nécessaire : `domain.write`. Accepte l'en-tête `Idempotency-Key` : une relance rejoue la réponse au lieu de refaire l'action. ### `POST /api/v1/domains/verify` Vérifier l'authentification d'un domaine Lit SPF, DKIM et DMARC dans le DNS public et rend le verdict enregistrement par enregistrement. Sans SPF et DMARC, les grands fournisseurs classent l'envoi en indésirable. Portée de clé nécessaire : `domain.write`. ### `GET /api/v1/domains/{domain}/dns` Enregistrements DNS attendus pour un domaine Ce qu'il faut poser chez le registrar, enregistrement par enregistrement, avec le rôle de chacun. Portée de clé nécessaire : `domain.read`. ## Délivrabilité Diagnostic, réputation et statistiques de remise. ### `GET /api/v1/deliverability/diagnose` Diagnostiquer la délivrabilité Répond à « pourquoi mes emails partent mal ? » : authentification de chaque domaine, constats de réputation (rebonds durs, plaintes, provenance des contacts) et actions recommandées, chacune avec l'endpoint qui la réalise. Portée de clé nécessaire : `analytics.read`. Paramètres : - `domain` : Restreint le diagnostic à un domaine déclaré. ### `GET /api/v1/stats/cohorts` Cohortes d'envoi par mois Cohortes d'envoi par mois Portée de clé nécessaire : `analytics.read`. ### `GET /api/v1/stats/deliverability` Statistiques de remise par domaine destinataire Statistiques de remise par domaine destinataire Portée de clé nécessaire : `analytics.read`. ### `GET /api/v1/suppressions` Lister les adresses sorties du circuit Rebonds durs, plaintes et désinscriptions. Un envoi vers une de ces adresses est refusé : les lire évite de réessayer une adresse morte et de faire monter le taux de rebonds. Portée de clé nécessaire : `contacts.read`. Paramètres : - `reason` : Filtre : hard_bounce, soft_bounce_limit, complaint, unsubscribe, manual. - `since` : Date ISO 8601 à partir de laquelle lire. - `limit` : Nombre de lignes, 1 à 200. - `cursor` : Curseur de pagination. ### `GET /v3/smtp/statistics/aggregatedReport` Rapport agrégé des envois Rapport agrégé des envois ## Compte Consommation, quotas, expéditeurs, journal des actions. ### `GET /api/v1/audit-logs` Journal des actions Une ligne par appel : quelle clé, quelle opération, quels paramètres, quel résultat. Le corps des messages n'y figure jamais. Portée de clé nécessaire : `analytics.read`. Paramètres : - `operation` : Filtre sur le nom d'opération (email.send, campaign.send...). - `since` : Date ISO 8601 à partir de laquelle lire. - `limit` : Nombre de lignes, 1 à 200. - `cursor` : Curseur de pagination. ### `GET /api/v1/usage` Consommation et plafonds Quota mensuel, envois du jour, et pour la clé utilisée : ses portées, son plafond journalier et ce qu'il en reste. Un agent qui ne sait pas ce qu'il lui reste ne peut pas décider de s'arrêter. Portée de clé nécessaire : `billing.read`. ### `GET /v3/account` Informations du compte Informations du compte ### `GET /v3/senders` Lister les expéditeurs Lister les expéditeurs ### `POST /v3/senders` Déclarer un expéditeur Déclarer un expéditeur ### `DELETE /v3/senders/{id}` Supprimer un expéditeur Supprimer un expéditeur ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ## Webhooks Abonnement aux événements d'envoi. ### `GET /v3/webhooks` Lister les webhooks Lister les webhooks ### `POST /v3/webhooks` Créer un webhook Créer un webhook ### `GET /v3/webhooks/{id}` Lire un webhook Lire un webhook ### `PUT /v3/webhooks/{id}` Modifier un webhook Modifier un webhook ### `DELETE /v3/webhooks/{id}` Supprimer un webhook Supprimer un webhook ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ## Prospection Séquences à froid : boîtes d'envoi, réponses relevées, désinscriptions. Module activable par compte. ### `GET /v3/outreach/campaigns` Lister les séquences Lister les séquences ### `POST /v3/outreach/campaigns` Créer une séquence Créer une séquence ### `GET /v3/outreach/campaigns/{id}` Lire une séquence Lire une séquence ### `PUT /v3/outreach/campaigns/{id}` Modifier une séquence Modifier une séquence ### `DELETE /v3/outreach/campaigns/{id}` Supprimer une séquence Supprimer une séquence ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ### `POST /v3/outreach/campaigns/{id}/enroll` Inscrire des prospects dans une séquence Inscrire des prospects dans une séquence Débit : 60 requêtes par minute. ### `GET /v3/outreach/campaigns/{id}/stats` Statistiques d'une séquence Statistiques d'une séquence ### `POST /v3/outreach/campaigns/{id}/status` Démarrer, mettre en pause ou arrêter une séquence Passer en « running » déclenche des envois réels aux prospects inscrits. ### `GET /v3/outreach/identity` Lire l'identification légale de l'expéditeur Lire l'identification légale de l'expéditeur ### `PUT /v3/outreach/identity` Déclarer l'identification légale de l'expéditeur Raison sociale et adresse postale, reprises au pied de chaque message (L.34-5 du CPCE). Tant qu'elles sont vides, l'inscription en campagne et le démarrage sont refusés. ### `GET /v3/outreach/inbox` Lister les réponses reçues Réponses relevées en IMAP sur les boîtes d'envoi du compte, classées (intéressé, refus, absence, désinscription). C'est la seule voie entrante de VaEmail à ce jour : elle est rattachée à une séquence, ce n'est pas une boîte générique. ### `GET /v3/outreach/inbox/{id}` Lire une réponse Lire une réponse ### `PUT /v3/outreach/inbox/{id}` Changer le classement ou l'état d'une réponse Changer le classement ou l'état d'une réponse ### `POST /v3/outreach/inbox/{id}/reply` Répondre à un prospect Envoie la réponse depuis la boîte qui a reçu le message, dans le même fil. Débit : 30 requêtes par minute. ### `GET /v3/outreach/mailboxes` Lister les boîtes d'envoi et leur santé Lister les boîtes d'envoi et leur santé ### `POST /v3/outreach/mailboxes` Déclarer une boîte d'envoi Déclarer une boîte d'envoi ### `GET /v3/outreach/mailboxes/{id}` Lire une boîte d'envoi Lire une boîte d'envoi ### `PUT /v3/outreach/mailboxes/{id}` Modifier une boîte d'envoi Modifier une boîte d'envoi ### `DELETE /v3/outreach/mailboxes/{id}` Supprimer une boîte d'envoi Supprimer une boîte d'envoi ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ### `GET /v3/outreach/prospects` Lister les prospects Lister les prospects ### `POST /v3/outreach/prospects` Ajouter des prospects Ajouter des prospects Débit : 60 requêtes par minute. ### `DELETE /v3/outreach/prospects` Supprimer des prospects en lot Supprimer des prospects en lot ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ### `GET /v3/outreach/prospects/{id}` Lire un prospect Lire un prospect ### `PUT /v3/outreach/prospects/{id}` Modifier un prospect Modifier un prospect ### `DELETE /v3/outreach/prospects/{id}` Supprimer un prospect Supprimer un prospect ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ## Médiathèque Images hébergées pour les campagnes. ### `GET /v3/media` Lister les images Lister les images ### `POST /v3/media` Téléverser une image Téléverser une image Débit : 60 requêtes par minute. ### `GET /v3/media/{uuid}` Lire une image Lire une image ### `DELETE /v3/media/{uuid}` Supprimer une image Supprimer une image ⚠ Action irréversible : à ne pas lancer sans validation humaine explicite. > Action irréversible. À ne pas déclencher sans validation humaine explicite. ## RGPD Export et effacement des données d'un contact. ### `POST /api/v1/contacts/erase` Effacer les données d'un contact Action irréversible : les données personnelles sont supprimées, l'adresse reste en liste de suppression pour ne pas être recontactée. Portée de clé nécessaire : `contacts.write`. ### `GET /api/v1/contacts/export` Exporter les données d'un contact Exporter les données d'un contact Portée de clé nécessaire : `contacts.read`.