{
  "openapi": "3.0.3",
  "info": {
    "title": "Mailpro™ Email API v2",
    "version": "2",
    "description": "L'API Email Mailpro™ v2 vous permet de gérer par programmation les listes de contacts, les modèles d'e-mail,\nles adresses d'expéditeur et les campagnes — et d'envoyer des e-mails de masse comme transactionnels.\n\n## Authentification\n\nChaque endpoint accepte **trois méthodes d'authentification**. Utilisez celle qui convient\nà votre stack.\n\n- **OAuth 2.0** — des tokens à scopes, révocables, pour les applications tierces et les\n  plateformes d'intégration (Zapier, Make, n8n). C'est la seule méthode que vous pouvez confier à\n  un tiers. **Les tokens OAuth sont contrôlés par scope sur chaque endpoint** (voir plus bas).\n- **Bearer JWT** (legacy) — un token HMAC obtenu via `POST /token`, sans scopes.\n- **IdClient + ApiKey** (legacy) — identifiant client + clé API.\n\n> Le Bearer JWT legacy et IdClient+ApiKey continuent de fonctionner sans changement et ne sont **pas**\n> soumis aux scopes. Seuls les tokens d'accès OAuth 2.0 sont soumis aux contrôles de scope par endpoint\n> indiqués sur chaque opération ci-dessous.\n\n### Méthode 1 — OAuth 2.0 (recommandée pour les intégrations)\n\nMailpro exploite **un seul** serveur d'autorisation OAuth 2.0 pour toutes ses API, sur une\nsurface unique, indépendante de la version : **`https://api.mailpro.com/oauth/`**. Il n'existe\npas d'endpoint OAuth par version — vous obtenez un token via `/oauth/token` et le\n**même** token fonctionne sur cette API Email v2, sur CRM v3 et sur SMS. Les\nendpoints qu'il peut appeler dépendent des **scopes** du token, pas de l'URL de base\nde l'API. Émetteur (claim `iss`) : `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Autorisation | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / renouvellement | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Découverte | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nGrants : `authorization_code` **+ PKCE (S256, obligatoire)**, `client_credentials`,\n`refresh_token` (rotation). Durée du token d'accès : **20 min** ; token de rafraîchissement : **30 jours**\n(glissants, à usage unique) ; code d'autorisation : **60 s**.\n\n**Démarrage rapide — obtenir un token et appeler cette API** (remplacez les valeurs ; ne\ncommitez jamais un vrai secret) :\n\n```bash\ncurl -X POST https://api.mailpro.com/oauth/token \\\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\n  -d \"grant_type=client_credentials\" \\\n  -d \"client_id=YOUR_CLIENT_ID\" \\\n  -d \"client_secret=YOUR_CLIENT_SECRET\" \\\n  -d \"scope=email:send email:read\"\n```\n\nAppelez ensuite cette API avec `Authorization: Bearer ACCESS_TOKEN`. Le même token\nfonctionne sur les API CRM v3 et SMS. Un token auquel il manque le scope exigé par un\nendpoint reçoit **403 `insufficient_scope`**. Parcours complet et catalogue des scopes :\nvoir la documentation de l'API **CRM v3** › Authentification. Scopes utiles pour l'e-mail :\n`email:send`, `email:read`, `email:templates:read`, `email:templates:write`,\n`contacts:read`, `contacts:write`, `account:read`.\n\n### Méthode 2 — Bearer JWT (legacy)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nObtenez un token via `POST /token` (encodé en formulaire, OAuth2 password grant) :\n\n```\nPOST https://api.mailpro.com/v2/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password&username=YOUR_USERNAME&password=YOUR_API_KEY\n```\n\nLe même token est également valide sur l'API CRM v3 et l'API SMS —\nauthentifiez-vous une seule fois, appelez n'importe quelle API. Les tokens sont valides **30 jours** par défaut ;\nutilisez `grant_type=refresh_token` pour les renouveler sans devoir vous réauthentifier. Sans scopes\n— préférez OAuth 2.0 pour les intégrations installables.\n\n### Méthode 3 — IdClient + ApiKey\n\nDeux identifiants :\n\n| Paramètre  | Type    | Description |\n|------------|---------|-------------|\n| `IdClient` | entier  | Votre identifiant client numérique Mailpro, accessible dans **Paramètres → Accès API** |\n| `ApiKey`   | chaîne  | Votre clé API, accessible dans **Paramètres → Accès API** |\n\nTransmettez-les à l'un de ces emplacements — choisissez-en un :\n\n1. **En-têtes HTTP (recommandé)** — `IdClient: 12345` et `ApiKey: a1b2c3d4-…`.\n   Les URL sont journalisées par les serveurs web, CDN et proxys, donc une clé placée dans la query string\n   peut fuiter dans les journaux d'accès. Les en-têtes ne sont pas journalisés.\n2. **Query string (legacy, toujours fonctionnel)** — `?IdClient=12345&ApiKey=…`.\n   Conservé pour la rétrocompatibilité avec les intégrations existantes. Migrez vers\n   les en-têtes dès que possible.\n3. **Corps de formulaire (POST uniquement)** — `IdClient=12345&ApiKey=…` en\n   `application/x-www-form-urlencoded`.\n\nSi vous fournissez les identifiants à plusieurs endroits, **l'en-tête l'emporte**.\n\n### Contrôle des scopes OAuth par endpoint (Email v2)\n\nPour les tokens émis par OAuth, chaque groupe d'endpoints exige un scope (l'authentification\nlegacy en est dispensée). Chaque opération indique son scope sous **Authorization**. Résumé :\n\n| Endpoints | Scope requis |\n|-----------|--------------|\n| `/send/*` (campagnes, transactionnel, planification, test — sauf `/send/{IdSend}/status`) | `email:send` |\n| `/stats/*` (sauf `/stats/del`), `/history/list`, `/send/{IdSend}/status` | `email:read` |\n| `/message/*`, `/senderEmail/*` (lecture) | `email:templates:read` |\n| `/message/*`, `/senderEmail/*` (add/edit/del), `/stats/del` | `email:templates:write` |\n| `/list/list`, `/email/list` | `contacts:read` |\n| `/list/{add,edit,del}`, `/email/{add,addSingle,edit,del}`, `/import/upload` | `contacts:write` |\n| `/account/*` | `account:read` |\n\nUn refus de scope renvoie **403** avec\n`{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }`.\n\n## Format de réponse\n\nTous les endpoints prennent en charge `json` (par défaut) et `xml`. Précisez le format dans l'URL :\n- `/email/list.json`\n- `/email/list.xml`\n\n## Pagination\n\n**Même règle sur les trois API Mailpro** (Email v2, CRM v3, SMS) : **5 000 éléments par page,\npar défaut comme au maximum.**\n- `numberOfRecords` — éléments par page. Absent, `0` ou au-delà de 5 000 = 5 000.\n- `pageNumber` — numéro de page à partir de 1 (par défaut 1).\n- Les deux sont acceptés en paramètre de query **ou** en en-tête HTTP.\n- Une page pleine signifie qu'il peut y en avoir d'autres : demandez la page suivante\n  jusqu'à recevoir une page incomplète.\n- Les pages sont stables : un même appel renvoie les mêmes éléments, dans le même ordre, tant que\n  les données ne changent pas entre-temps.\n- Exception : les listes de messages et d'historique avec leur HTML (`bodyHTML=true`) renvoient\n  10 éléments par page.\n- `/email/list` ajoute `X-Total-Count` (le total réel) et `X-Truncated: true` quand il reste\n  des contacts au-delà de la page.\n\n**Paramètres inconnus** : ils sont ignorés, jamais refusés. Quand une requête porte un\nparamètre que l'API ne reconnaît pas, la réponse contient `X-Ignored-Parameters` (les noms)\net `X-Documentation` (un lien vers cette page), pour qu'une faute de frappe ne passe pas inaperçue.\n\n## Réponses d'erreur\n\n| HTTP | Signification |\n|------|---------------|\n| 400  | Requête incorrecte — paramètre obligatoire manquant ou invalide |\n| 401  | Non autorisé — `IdClient` ou `ApiKey` invalide |\n| 403  | Interdit — limite du compte atteinte (par exemple, nombre maximal de listes) |\n| 404  | Introuvable — la ressource demandée n'existe pas |\n| 500  | Erreur interne du serveur |\n\nErreurs liées aux règles métier :\n- `\"Not enough credit available.\"` → 403 — votre compte n'a plus de crédits e-mail disponibles\n- `\"Email address unsubscribed.\"` → 400 — le destinataire s'est désabonné\n\n## Suivi des envois (e-mails transactionnels)\n\nChaque e-mail **unitaire** envoyé (`POST /send/sendmail`, l'API CRM v3, le relais SMTP ou une automation) reçoit un identifiant. Il peut être suivi jusqu'à ce que le serveur du destinataire l'accepte ou le refuse. Les campagnes ne sont pas concernées : utilisez les statistiques.\n\n1. **Envoyer** : la réponse de `POST /send/sendmail.{format}` contient l'identifiant de l'envoi.\n2. **Recevoir le résultat** (recommandé) : les événements webhook `email.delivered` et `email.bounced` envoient le statut final à votre serveur dès qu'il est connu, sans aucune interrogation.\n3. **Ou interroger** : `GET /send/{IdSend}/status.{format}` rend le statut du moment (tableau ci-dessous).\n\n| `status` | Signification | Final ? |\n|---|---|---|\n| `queued` | Accepté, en attente d'expédition. | non |\n| `scheduled` | Planifié pour plus tard (`DatePlanned`). | non |\n| `sent` | Remis par nos serveurs, pas encore de réponse du serveur du destinataire. | non |\n| `delivered` | Accepté par le serveur du destinataire (`DiagCode` = sa réponse SMTP). | **oui** |\n| `bounced` | Refusé. `BounceType` : `hard` = adresse invalide ou refus définitif ; `soft` = refus après nouvelles tentatives (boîte pleine, serveur injoignable…). | **oui** |\n| `not_found` | Identifiant inconnu ou qui n'appartient pas à votre compte. | **oui** |\n\n**Interroger sans boucler**\n\n- Arrêtez d'interroger dès que le statut est **final** : il ne changera plus.\n- Première interrogation **5 minutes** après l'envoi au plus tôt : `delivered` apparaît environ 5 minutes après la remise.\n- Ensuite, **une interrogation toutes les 15 minutes au plus**.\n- Si vous interrogez un envoi non final avant 15 minutes, vous recevez la même réponse, avec l'en-tête `Retry-After` (le nombre de secondes à attendre), et l'appel ne compte pas dans votre quota.\n- **Au plus tard 48 heures** après l'envoi, chaque e-mail a un statut final : au-delà, n'interrogez plus.\n- `scheduled` : inutile d'interroger avant `DatePlanned`.\n- **Chaque interrogation compte dans votre quota de requêtes API.** En suivant ces règles, un envoi coûte au plus 192 requêtes (4 par heure pendant 48 heures), et bien moins en pratique, puisque l'on s'arrête au statut final. Le même suivi par webhook coûte 1 seul événement.\n\nLes statuts sont conservés **365 jours**.\n\n## Webhooks\n\nMailpro™ peut notifier votre serveur en temps réel lorsque certains événements se produisent sur votre\ncompte (un e-mail est délivré, une campagne se termine, un contact rebondit, etc.).\nFaçon Stripe — votre URL reçoit un POST signé en HMAC-SHA256 dès que\nl'événement est déclenché.\n\nChaque événement envoyé à votre webhook compte pour 1 requête dans votre quota de requêtes API.\n\n### Fonctionnement\n\n1. **Abonnez-vous** à un ou plusieurs types d'événements via `POST /webhooks`. La réponse\n   contient un `secret` affiché **une seule fois** (façon Stripe / GitHub) — conservez-le.\n2. **Mailpro envoie en POST** une charge utile JSON signée à votre URL dès qu'un événement correspond.\n3. **Vérifiez la signature** côté serveur avec votre `secret` (extraits ci-dessous).\n4. **Répondez 200–299** sous 10 secondes. Sinon, nous réessayons avec un backoff exponentiel\n   (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, puis abandon).\n\n> **⏱ Délai d'activation** — après création, mise à jour ou suppression d'un webhook, la\n> modification met jusqu'à **10 minutes** à se propager sur l'ensemble des serveurs\n> de l'API Mailpro. Pendant cette fenêtre, les événements peuvent ne pas encore correspondre à votre nouvel abonnement\n> (ou peuvent toujours correspondre à un abonnement qui vient d'être retiré). C'est le temps nécessaire pour\n> rafraîchir le cache d'abonnements en mémoire sur chaque instance de l'API.\n\n### Enveloppe de la charge utile\n\nTous les événements partagent une enveloppe commune :\n\n```json\n{\n  \"id\":         \"evt_8f3a9b2c4d1e5f6789abcdef01234567\",\n  \"type\":       \"email.delivered\",\n  \"created\":    1748194800,\n  \"apiVersion\": \"v2\",\n  \"account\":    { \"id\": 12345, \"name\": \"ACME Corp\" },\n  \"data\":       { \"messageId\": \"...\", \"email\": \"alice@example.com\", \"...\": \"...\" }\n}\n```\n\n| Champ | Format | Description |\n|-------|--------|-------------|\n| `id` | `evt_` + 32 hex | Identifiant unique de l'événement — à utiliser comme clé d'idempotence de votre côté. |\n| `type` | `<domain>.<verb>` | Type d'événement canonique. |\n| `created` | Secondes Unix UTC | Inclus dans la signature HMAC. |\n| `apiVersion` | `\"v2\"` | L'API Mailpro qui a publié l'événement. |\n| `account.id` | int | Votre identifiant client Mailpro (= `IdClient`). |\n| `account.name` | string | Le nom de votre compte (pratique pour le débogage côté client). |\n| `data` | object | Charge utile de l'événement — sa structure dépend du `type` (voir le catalogue ci-dessous). |\n\n### Catalogue des événements\n\n| Événement | Déclencheur | Structure de `data` |\n|-----------|-------------|---------------------|\n| `ping` | Test via `POST /webhooks/{id}/test` | `{ message }` |\n| `email.processed` | Envoi accepté par le pipeline | `{ messageId, email, campaignId, processedAt }` |\n| `email.delivered` | Un email **unitaire** a été accepté par le serveur destinataire — API v2/v3, SMTP ou Automation (**pas** les campagnes). Émis depuis le flux de livraison PowerMTA. | `{ messageId, email, idSending, sendingType, diagCode, deliveredAt }` |\n| `email.opened` | Pixel de tracking déclenché | `{ messageId, email, campaignId, openedAt, ip, userAgent }` |\n| `email.clicked` | Clic sur un lien tracké | `{ messageId, email, campaignId, clickedAt, url, ip, userAgent }` |\n| `email.bounced` | Rebond dur ou souple | `{ messageId, email, campaignId, bouncedAt, bounceType, reason }` |\n| `email.spam_report` | Plainte FBL | `{ messageId, email, campaignId, reportedAt }` |\n| `email.unsubscribed` | Lien de désinscription cliqué | `{ messageId, email, campaignId, unsubscribedAt }` |\n| `email.dropped` | Refusé avant envoi | `{ messageId, email, campaignId, droppedAt, reason }` |\n| `campaign.started` | Le dispatch commence | `{ campaignId, name, totalRecipients, startedAt }` |\n| `campaign.finished` | Tous les destinataires traités | `{ campaignId, name, totalSent, totalFailed, finishedAt }` |\n| `credits.low` | Solde de crédits e-mail sous votre seuil d'alerte | `{ remaining, threshold }` |\n\nAbonnez-vous à tous les événements de cette API en passant `[\"*\"]` dans le tableau `events`.\n\n### Signature HMAC\n\nChaque POST embarque un en-tête `X-Mailpro-Signature` :\n\n```\nX-Mailpro-Signature: t=1748194800,v1=7f9ac2b6e4d1c8a3...\nX-Mailpro-Event-Id:  evt_8f3a9b2c4d1e5f6789abcdef01234567\nX-Mailpro-Event-Type: email.delivered\nX-Mailpro-Attempt:   1\n```\n\nPour vérifier :\n1. Extrayez `t` et `v1` de l'en-tête.\n2. **Rejetez** si `|now - t| > 300` (fenêtre de 5 minutes de protection contre le rejeu).\n3. Calculez `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Comparez en temps constant** `v1` à `expected` (`crypto.timingSafeEqual`,\n   `hash_equals`, `CryptographicOperations.FixedTimeEquals`) — jamais avec `==`.\n\n#### Node.js\n\n```js\nconst crypto = require('crypto');\n\nfunction verifyMailproSignature(rawBody, header, secret) {\n  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));\n  if (Math.abs(Date.now() / 1000 - parseInt(parts.t)) > 300) return false;\n  const expected = crypto\n    .createHmac('sha256', secret)\n    .update(parts.t + '.' + rawBody)\n    .digest('hex');\n  return crypto.timingSafeEqual(\n    Buffer.from(parts.v1, 'hex'),\n    Buffer.from(expected, 'hex'));\n}\n```\n\n#### PHP\n\n```php\nfunction verifyMailproSignature(string $rawBody, string $header, string $secret): bool {\n    parse_str(str_replace(',', '&', $header), $p);\n    if (abs(time() - (int)$p['t']) > 300) return false;\n    $expected = hash_hmac('sha256', $p['t'] . '.' . $rawBody, $secret);\n    return hash_equals($expected, $p['v1']);\n}\n```\n\n#### Python\n\n```python\nimport hmac, hashlib, time\n\ndef verify_mailpro_signature(raw_body: bytes, header: str, secret: str) -> bool:\n    parts = dict(p.split('=') for p in header.split(','))\n    t = int(parts['t'])\n    if abs(time.time() - t) > 300:\n        return False\n    expected = hmac.new(\n        secret.encode(),\n        f\"{t}.\".encode() + raw_body,\n        hashlib.sha256\n    ).hexdigest()\n    return hmac.compare_digest(expected, parts['v1'])\n```\n\n#### C#\n\n```csharp\nusing System.Security.Cryptography;\nusing System.Text;\n\nstatic bool VerifyMailproSignature(string rawBody, string header, string secret) {\n    var parts = header.Split(',')\n        .Select(p => p.Split('='))\n        .ToDictionary(a => a[0], a => a[1]);\n    var t = long.Parse(parts[\"t\"]);\n    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return false;\n    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));\n    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes($\"{t}.{rawBody}\"));\n    var expected = Convert.ToHexString(hash).ToLowerInvariant();\n    return CryptographicOperations.FixedTimeEquals(\n        Encoding.UTF8.GetBytes(expected),\n        Encoding.UTF8.GetBytes(parts[\"v1\"]));\n}\n```\n\n### Réessais et désactivation automatique\n\n| Tentative | Délai avant la prochaine tentative |\n|-----------|------------------------------------|\n| 1 → 2 | 10 secondes |\n| 2 → 3 | 1 minute |\n| 3 → 4 | 5 minutes |\n| 4 → 5 | 30 minutes |\n| 5 → 6 | 2 heures |\n| 6 → 7 | 6 heures |\n| 7 | abandonnée (livraison marquée `failed`) |\n\nAprès **10 échecs consécutifs** sur le même webhook, celui-ci est **automatiquement\ndésactivé** (`isActive: false`) et vous recevez un e-mail de notification. Réactivez-le\navec `PUT /webhooks/{id}` une fois votre endpoint corrigé.\n\n### Succès = HTTP 2xx\n\nNous considérons votre webhook comme réussi uniquement si vous renvoyez un statut compris dans `200–299`.\nTout 3xx/4xx/5xx ou un délai d'attente dépassé (> 10 s) compte comme un échec et déclenche des réessais.\nSi votre endpoint est définitivement hors service, renvoyez explicitement `410 Gone` — les réessais\nont toujours lieu, mais le motif d'échec est plus clair dans votre journal de livraison.\n\n### Limites\n\n| Limite | Valeur |\n|--------|--------|\n| Webhooks par compte | 20 |\n| Événements souscrits par webhook | 50 |\n| Taille maximale de la charge utile | 256 Ko |\n| Délai HTTP par tentative | 10 secondes |\n| Rétention de l'historique de livraison | 30 jours |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/v2",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Jeton JWT Bearer obtenu via `POST /v2/token` (encodage form-urlencoded, grant\n`password`). Le même jeton est également valable sur l’API CRM v3 et l’API\nSMS — authentifiez-vous une fois, appelez n’importe quelle API.\nÀ transmettre ainsi : `Authorization: Bearer <token>`\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Mailpro OAuth 2.0 — la méthode moderne pour permettre aux applications\ntierces et aux plateformes d’intégration (Zapier, Make, n8n) d’agir au nom\nd’un utilisateur Mailpro à l’aide de jetons d’accès à portée limitée et\nrévocables.\n\n- **authorizationCode + PKCE** (S256, obligatoire pour les clients publics) —\n  le flux de consentement « Connect Mailpro ». Émet un jeton d’accès ainsi\n  qu’un refresh token rotatif.\n- **clientCredentials** — machine à machine, sans utilisateur impliqué.\n\nUn unique serveur d’autorisation pour toutes les API, exposé sur la surface\nneutre en versions `https://api.mailpro.com/oauth/` (émetteur / claim `iss`\n`https://api.mailpro.com/oauth/`). Les jetons d’accès sont des JWT RS256\n(à vérifier contre le JWKS situé à `https://api.mailpro.com/oauth/.well-known/jwks`) ;\nleur TTL est de **20 minutes**. Les refresh tokens sont valables **30 jours**\n(glissants) et **à usage unique** (renouvelés à chaque rafraîchissement).\nLes codes d’autorisation vivent **60 secondes**.\n\nLe même jeton d’accès OAuth est accepté par les trois API Mailpro (CRM v3,\nEmail v2, SMS) — authentifiez-vous une seule fois, appelez n’importe quelle\nAPI ; l’accès est régi par les scopes du jeton et non par l’URL de base de\nl’API. L’authentification historique (Bearer JWT / IdClient+ApiKey) continue\nde fonctionner à l’identique et n’est PAS soumise aux scopes.\n",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.mailpro.com/oauth/authorize",
            "tokenUrl": "https://api.mailpro.com/oauth/token",
            "refreshUrl": "https://api.mailpro.com/oauth/token",
            "scopes": {
              "contacts:read": "View your contacts, lists, tags, segments and custom fields.",
              "contacts:write": "Create, edit and delete your contacts, lists, tags and custom fields.",
              "email:send": "Send transactional and campaign emails on your behalf.",
              "email:read": "View delivery stats, opens, clicks and bounce history.",
              "email:templates:read": "View your email templates (subject, HTML, plain-text body).",
              "email:templates:write": "Create, edit and delete your email templates.",
              "sms:send": "Send transactional and campaign SMS messages on your behalf.",
              "sms:read": "View SMS credit balance and message history.",
              "sms:contacts:read": "View your SMS phone book.",
              "sms:contacts:write": "Create, edit and delete entries in your SMS phone book.",
              "webhooks:manage": "Subscribe to, edit and remove webhook endpoints for your account.",
              "account:read": "View your account credits, limits and subscription status."
            }
          },
          "clientCredentials": {
            "tokenUrl": "https://api.mailpro.com/oauth/token",
            "scopes": {
              "contacts:read": "View your contacts, lists, tags, segments and custom fields.",
              "contacts:write": "Create, edit and delete your contacts, lists, tags and custom fields.",
              "email:send": "Send transactional and campaign emails on your behalf.",
              "email:read": "View delivery stats, opens, clicks and bounce history.",
              "email:templates:read": "View your email templates (subject, HTML, plain-text body).",
              "email:templates:write": "Create, edit and delete your email templates.",
              "sms:send": "Send transactional and campaign SMS messages on your behalf.",
              "sms:read": "View SMS credit balance and message history.",
              "sms:contacts:read": "View your SMS phone book.",
              "sms:contacts:write": "Create, edit and delete entries in your SMS phone book.",
              "webhooks:manage": "Subscribe to, edit and remove webhook endpoints for your account.",
              "account:read": "View your account credits, limits and subscription status."
            }
          }
        }
      },
      "IdClientHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "IdClient",
        "description": "Votre identifiant client Mailpro numérique — transport **recommandé** (en-tête HTTP).\nLes URLs sont journalisées par les serveurs web, Cloudflare et les proxys, ce qui peut\nfaire fuiter les identifiants dans les journaux d’accès. Les en-têtes, eux, ne sont pas journalisés.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "ApiKey",
        "description": "Votre clé API (GUID) — transport **recommandé** (en-tête HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "IdClient",
        "description": "Votre identifiant client Mailpro numérique — **hérité**, conservé pour rétrocompatibilité.\nMigrez vers l’en-tête `IdClient` dès que possible.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "ApiKey",
        "description": "Votre clé API (GUID) — **héritée**, conservée pour rétrocompatibilité.\n"
      }
    },
    "parameters": {
      "format": {
        "name": "format",
        "in": "path",
        "required": true,
        "description": "Format de réponse",
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "xml"
          ],
          "default": "json"
        },
        "example": "json"
      },
      "numberOfRecords": {
        "name": "numberOfRecords",
        "in": "query",
        "description": "Éléments par page — 5 000 par défaut et au maximum (voir Pagination).",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 50
      },
      "pageNumber": {
        "name": "pageNumber",
        "in": "query",
        "description": "Numéro de page (à partir de 1). Par défaut : 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Jeton d’accès JWT — à utiliser comme `Authorization: Bearer <token>` dans les requêtes suivantes."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Durée de vie du jeton, en secondes",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "Identifiant client de l’utilisateur authentifié",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Jeton permettant d’obtenir un nouveau jeton d’accès sans se réauthentifier"
          },
          "application": {
            "type": "string",
            "description": "Nom de l’intégration (uniquement pour les grants tiers)",
            "nullable": true
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "ListID": {
            "type": "integer",
            "description": "Identifiant unique de la liste",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias hérité** — valeur identique à `ListID`. Renvoyé pour la rétrocompatibilité avec les clients anciens.",
            "example": 101
          },
          "Title": {
            "type": "string",
            "description": "Nom d’affichage de la liste",
            "example": "Newsletter — France"
          },
          "Type": {
            "type": "integer",
            "description": "`0` = liste de contacts standard, `1` = liste noire (gestion des désabonnements)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "NumberEmails": {
            "type": "integer",
            "description": "Nombre total de contacts dans cette liste",
            "example": 4521
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "description": "Date et heure de création de la liste",
            "example": "2025-01-15T10:30:00"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "IDMessage": {
            "type": "integer",
            "description": "Identifiant unique du modèle de message",
            "example": 501
          },
          "Subject": {
            "type": "string",
            "description": "Ligne d’objet de l’e-mail",
            "example": "Spring Newsletter — April 2026"
          },
          "Language": {
            "type": "string",
            "description": "Code de langue utilisé pour la localisation du lien de désabonnement",
            "example": "EN"
          },
          "LinkAlign": {
            "type": "string",
            "description": "Alignement horizontal du lien de désabonnement",
            "enum": [
              "left",
              "center",
              "right"
            ],
            "example": "center"
          },
          "LinkUp": {
            "type": "integer",
            "description": "Position du lien de désabonnement — `0` = en bas, `1` = en haut",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "BodyHTML": {
            "type": "string",
            "description": "Contenu HTML complet de l’e-mail (renvoyé uniquement lorsque `bodyHTML=true`)",
            "example": "<h1>Welcome!</h1><p>This is our spring newsletter.</p>"
          },
          "UpdateDate": {
            "type": "string",
            "format": "date-time",
            "description": "Date et heure de la dernière modification du modèle",
            "example": "2026-03-10T14:22:00"
          }
        }
      },
      "SenderEmail": {
        "type": "object",
        "properties": {
          "IDEmailExp": {
            "type": "integer",
            "description": "Identifiant unique de l’adresse e-mail expéditrice",
            "example": 201
          },
          "Email": {
            "type": "string",
            "description": "Adresse e-mail de l’expéditeur (doit être validée avant utilisation)",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nom d’affichage présenté comme expéditeur dans les clients de messagerie des destinataires",
            "example": "Your Company Newsletter"
          },
          "IsValid": {
            "type": "boolean",
            "description": "`true` si l’adresse e-mail a été validée par Mailpro",
            "example": true
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "example": "2025-06-01T09:00:00"
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "IDSend": {
            "type": "integer",
            "description": "Identifiant unique de cet envoi/campagne",
            "example": 3001
          },
          "ListID": {
            "type": "integer",
            "description": "Identifiant de la liste de destinataires utilisée",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias hérité** — valeur identique à `ListID`.",
            "example": 101
          },
          "IDCampaign": {
            "type": "integer",
            "description": "Identifiant de la fiche statistiques de campagne (si `Campaign=1` a été défini à l’envoi)",
            "example": 8001
          },
          "SenderEmail": {
            "type": "string",
            "description": "Adresse e-mail de l’expéditeur",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nom d’affichage de l’expéditeur",
            "example": "Your Company Newsletter"
          },
          "DatePlanned": {
            "type": "string",
            "format": "date-time",
            "description": "Date et heure d’envoi planifiées",
            "example": "2026-04-20T09:00:00"
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Ligne d’objet de l’e-mail",
            "example": "Spring Newsletter — April 2026"
          },
          "NumberCredit": {
            "type": "integer",
            "description": "Nombre de crédits e-mail consommés par cet envoi",
            "example": 4521
          }
        }
      },
      "HistoryEntry": {
        "type": "object",
        "properties": {
          "IDHistoric": {
            "type": "integer",
            "description": "Identifiant unique de cette entrée d’historique",
            "example": 9001
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Ligne d’objet de l’e-mail envoyé",
            "example": "Spring Newsletter — April 2026"
          },
          "DateSend": {
            "type": "string",
            "format": "date-time",
            "description": "Date et heure d’envoi de l’e-mail",
            "example": "2026-04-20T09:00:01"
          },
          "NumberSend": {
            "type": "integer",
            "description": "Nombre total d’e-mails envoyés dans cette campagne",
            "example": 4521
          },
          "NumberOpen": {
            "type": "integer",
            "description": "Nombre d’ouvertures uniques enregistrées",
            "example": 1823
          },
          "NumberClick": {
            "type": "integer",
            "description": "Nombre de clics uniques enregistrés sur les liens",
            "example": 342
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Identifiant du webhook (Mailpro)",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS qui reçoit les événements",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Types d’événements souscrits",
            "example": [
              "email.delivered",
              "email.bounced",
              "campaign.finished"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Slack integration"
          },
          "is_active": {
            "type": "boolean",
            "description": "Lorsque ce champ vaut `false`, aucun événement n’est délivré. Désactivé automatiquement après 10 échecs consécutifs.",
            "example": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-07-01T21:09:52.43"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-07-21T18:56:08.02"
          },
          "last_delivery_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Quand la dernière tentative de livraison a eu lieu",
            "example": "2026-07-21T18:56:07.653"
          },
          "last_delivery_status": {
            "type": "integer",
            "nullable": true,
            "description": "Statut HTTP renvoyé par votre endpoint lors de la dernière livraison",
            "example": 200
          },
          "consecutive_failures": {
            "type": "integer",
            "description": "Remis à 0 au premier succès ; à 10, le webhook est désactivé automatiquement",
            "example": 0
          }
        }
      },
      "WebhookList": {
        "type": "object",
        "description": "Enveloppe renvoyée par `GET /webhooks`.",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "total": {
            "type": "integer",
            "description": "Nombre total de webhooks sur le compte",
            "example": 2
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS (HTTP refusé en production)",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "Liste des types d’événements à souscrire (voir le catalogue ci-dessus). Utilisez `[\"*\"]` pour vous abonner à tous les événements de cette API.",
            "example": [
              "email.delivered",
              "email.bounced"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 500,
            "example": "Slack integration"
          }
        }
      },
      "WebhookCreateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "Secret HMAC. **Affiché une seule fois ici, jamais à nouveau.** Stockez-le côté serveur.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Mise à jour partielle — chaque champ est facultatif.",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "isActive": {
            "type": "boolean",
            "description": "Passez à `true` pour réactiver un webhook désactivé automatiquement, une fois votre endpoint corrigé."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "eventId": {
            "type": "string",
            "example": "evt_8f3a9b2c4d1e5f6789abcdef01234567"
          },
          "eventType": {
            "type": "string",
            "example": "email.delivered"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "retrying",
              "failed"
            ]
          },
          "statusCode": {
            "type": "integer",
            "nullable": true,
            "example": 200
          },
          "responseTimeMs": {
            "type": "integer",
            "nullable": true,
            "example": 142
          },
          "attemptCount": {
            "type": "integer"
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "nextAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Authentication",
      "description": "Obtenez un jeton JWT Bearer pour authentifier tous les autres appels d’API. L’endpoint\nv2 `/token` est une redirection 307 vers l’émetteur canonique `/v3/token` — votre\nclient HTTP suit la redirection de manière transparente (la méthode POST et le\ncorps sont préservés).\n"
    },
    {
      "name": "Account",
      "description": "Consultez le solde de crédits e-mail, le quota mensuel d’API et l’état de votre abonnement."
    },
    {
      "name": "Lists",
      "description": "Gérez les listes (listes de contacts). Une liste regroupe des contacts pour les campagnes en masse.\n**Maximum 1 000 listes par compte** (même limite sur les trois API Mailpro et dans l'app).\n`Type 0` = liste standard. `Type 1` = liste noire (utilisée pour la gestion des désabonnements).\n"
    },
    {
      "name": "Contacts",
      "description": "Gérez les contacts e-mail individuels. Les contacts appartiennent à une ou plusieurs listes.\nUtilisez l’import en masse (`/email/add`) pour les gros lots, ou l’ajout de contact unique\n(`/email/addSingle`) pour les inscriptions individuelles avec valeurs de champs personnalisés.\n"
    },
    {
      "name": "Messages",
      "description": "Gérez les modèles d’e-mails HTML. Un modèle de message stocke l’objet, le corps HTML\net la configuration du lien de désabonnement.\nLes modèles sont réutilisés d’une campagne à l’autre.\n"
    },
    {
      "name": "Campaigns",
      "description": "Envoyez des campagnes e-mail en masse à une liste et gérez les envois planifiés.\nUne campagne s’appuie sur un modèle de message et une adresse expéditrice.\n"
    },
    {
      "name": "Transactional",
      "description": "Envoyez des e-mails transactionnels ponctuels à des destinataires individuels.\nContrairement aux campagnes, les e-mails transactionnels ne nécessitent pas de liste —\nvous transmettez directement l’adresse du destinataire et le corps HTML.\n"
    },
    {
      "name": "Sender Addresses",
      "description": "Listez et gérez les adresses e-mail expéditrices validées.\nSeules les adresses vérifiées peuvent être utilisées comme adresse `From` dans les campagnes.\n"
    },
    {
      "name": "Statistics",
      "description": "Accédez aux indicateurs de performance par campagne : ouvertures, clics, rebonds, etc.\nDes ventilations détaillées par heure, par jour, par pays, par OS et par client de messagerie sont disponibles.\n"
    },
    {
      "name": "History",
      "description": "Parcourez le journal complet de tous les envois d’e-mails passés.\n"
    },
    {
      "name": "Import",
      "description": "Téléversez un fichier CSV ou XLSX pour importer des contacts e-mail dans une liste en masse.\nLe fichier est placé en file d’attente pour un traitement asynchrone — suivez la fin\nde traitement via l’`ImportJobId` renvoyé ou via le callback `WebhookUrl` optionnel.\n"
    },
    {
      "name": "Webhooks",
      "description": "Abonnez votre serveur aux notifications d’événements en temps réel. Mailpro envoie en POST\nune charge utile JSON signée HMAC à votre URL dès que l’événement souscrit se produit.\nConsultez la section « Webhooks » de l’introduction pour le catalogue complet des événements,\nl’enveloppe de la charge utile, les extraits de vérification de signature et la politique de réessai.\n"
    },
    {
      "name": "Suppression",
      "description": "Bounces et désinscrits du compte : lister, ajouter, retirer."
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getEmailAccessToken",
        "summary": "Obtenir un jeton d’accès (redirection 307 vers /v3/token)",
        "security": [],
        "description": "Obtient un jeton JWT Bearer à partir des identifiants client Mailpro.\nTransmettez l’`access_token` renvoyé comme `Authorization: Bearer <token>` dans\ntoutes les requêtes suivantes. Le même jeton est également valable sur l’API CRM v3 et\nl’API SMS.\n\n> **⚙ Détail d’implémentation** — `POST /v2/token` est une **redirection 307\n> Temporary Redirect** vers `POST /v3/token` (configurée au niveau de la couche\n> de réécriture IIS `web.config`). HTTP 307 préserve à la fois la **méthode**\n> (`POST`) et le **corps de la requête**, si bien que tout client HTTP conforme\n> aux standards suit la redirection de manière transparente — vous continuez à\n> poster sur `/v2/token` et récupérez un JWT valide. Il n’y a aucune logique\n> d’émission de jeton dupliquée ; l’API Email v2 n’émet jamais de jetons elle-même.\n\n### Types de grant pris en charge\n| Type de grant | Cas d’usage |\n|------------|----------|\n| `password` | Intégration standard — nom d’utilisateur + clé API |\n| `refresh_token` | Renouveler un jeton d’accès expirant sans se réauthentifier |\n| `client_credentials` | Serveur à serveur avec uniquement l’identifiant client |\n\n### Durée de vie des jetons\n- Jeton d’accès : **30 jours**\n- Jeton de rafraîchissement : **90 jours**\n\nUtilisez `grant_type=refresh_token` pour renouveler le jeton d’accès sans vous\nréauthentifier. Stockez les jetons côté serveur (Vault, variables d’environnement) ;\nne les intégrez jamais dans du JS navigateur ni dans des binaires d’application mobile.\nVoir la doc `/token` de l’API CRM v3 pour la note de sécurité complète.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "password",
                      "refresh_token",
                      "client_credentials"
                    ],
                    "example": "password"
                  },
                  "username": {
                    "type": "string",
                    "description": "Votre nom d’utilisateur Mailpro (e-mail). Requis pour le grant `password`.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "Votre clé API Mailpro (format GUID). Requise pour le grant `password`.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Jeton de rafraîchissement précédent. Requis pour le grant `refresh_token`."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Votre identifiant client Mailpro (entier). Requis pour le grant `client_credentials`.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Jeton émis avec succès. Renvoyé par `POST /v3/token` après le suivi\ntransparent du 307 — votre client HTTP voit un 200 normal avec la même\nforme de corps qu’il recevrait directement depuis l’endpoint de jeton\nv3.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "example": {
                  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "token_type": "bearer",
                  "expires_in": 31535999,
                  "userName": "12345",
                  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "application": null
                }
              }
            }
          },
          "307": {
            "description": "Redirection temporaire (Temporary Redirect) vers `POST /v3/token`, émise par la règle\nde réécriture IIS dans `web.config`. Les clients HTTP conformes aux standards suivent\nautomatiquement cette redirection et préservent la méthode POST d’origine ainsi que le\ncorps de formulaire. Visible uniquement par les clients qui désactivent explicitement\nle suivi des redirections (par ex. `curl --max-redirs 0`).\n",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "example": "https://api.mailpro.com/v3/token"
              }
            }
          },
          "400": {
            "description": "Identifiants invalides ou type de grant non pris en charge",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Identifiants incorrects",
                    "value": {
                      "error": "invalid_grant",
                      "error_description": "The username or password is incorrect."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/account/credits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountCredits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtenir le solde de crédits e-mail",
        "description": "Renvoie le solde de crédits e-mail restants pour votre compte Mailpro.\nChaque e-mail envoyé consomme un crédit. Les crédits n’expirent pas avec l’abonnement,\nmais ne sont utilisables que tant que l’abonnement est actif.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Solde de crédits renvoyé avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Credits": 48500
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/account/subscriptionEndDate.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSubscriptionEndDate",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtenir la date de fin d’abonnement",
        "description": "Renvoie la date d’expiration de l’abonnement Mailpro en cours.\nAprès la date d’expiration, les envois sont bloqués jusqu’au renouvellement de l’abonnement.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Date de fin d’abonnement renvoyée avec succès",
            "content": {
              "application/json": {
                "example": {
                  "SubscriptionEndDate": "2027-01-15T00:00:00"
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtenir le quota mensuel d’API",
        "description": "Renvoie le quota mensuel de requêtes API pour le client authentifié.\n\n**Calcul du quota :** la limite est calibrée à partir des crédits e-mail de\nl’abonnement (typiquement `crédits_abonnement × 5`). Pour un forfait de\n10 000 e-mails/mois, cela donne un budget mensuel de 50 000 requêtes. Réinitialisé\nà la **date anniversaire de l’abonnement** (et non le 1er du mois calendaire).\n\n**Ce qui consomme du quota :**\n- Chaque requête API authentifiée vers les endpoints `v2`, `v3` ou `sms`.\n- Chaque événement webhook distribué à un endpoint abonné.\n\n**Ce qui est GRATUIT (ne consomme pas de quota) :**\n- Les endpoints `/health`.\n- Les requêtes qui échouent avec `401`, `403` ou `429`.\n- Les événements webhook pour les clients sans abonnement correspondant.\n\nLe quota est **partagé entre les 3 API Mailpro** (`v2`, `v3`, `sms`)\n— un client = un budget mensuel pour l’ensemble de la plateforme.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Instantané du quota",
            "content": {
              "application/json": {
                "example": {
                  "MonthlyLimit": 50000,
                  "Remaining": 32847,
                  "Used": 17153,
                  "IsFree": false,
                  "RemainedSendsForFree": 0
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Aucun enregistrement de quota trouvé (compte récemment créé ; la ligne sera créée à la première requête authentifiée)."
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listLists",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister toutes les listes",
        "description": "Renvoie toutes les listes du compte, triées par date de création (les plus récentes en premier),\nsauf si `sortByName=true` est défini.\nUtilisez `type=0` pour les listes classiques ou `type=1` pour les listes noires.\n\n> **Alias hérité :** `/addressbook/list.{format}` — même endpoint, conservé pour rétrocompatibilité.\n> Les nouvelles intégrations doivent utiliser `/list/*`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleFilter",
            "in": "query",
            "description": "Filtrer par titre (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`0` = listes standard uniquement, `1` = listes noires uniquement. Omettre pour toutes les renvoyer.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Passer à `true` pour trier les résultats par ordre alphabétique du titre",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listes renvoyées avec succès.\n\n> La réponse contient également un champ dupliqué hérité `AddressBookList` (contenu identique)\n> et chaque élément possède un `AddressBookID` dupliqué hérité (identique à `ListID`). Les nouvelles\n> intégrations doivent les ignorer.\n",
            "content": {
              "application/json": {
                "example": {
                  "Lists": [
                    {
                      "ListID": 101,
                      "Title": "Newsletter — France",
                      "Type": 0,
                      "NumberEmails": 4521,
                      "CreationDate": "2025-01-15T10:30:00"
                    },
                    {
                      "ListID": 102,
                      "Title": "Unsubscribers",
                      "Type": 1,
                      "NumberEmails": 312,
                      "CreationDate": "2025-01-15T10:31:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Créer une liste",
        "description": "Crée une nouvelle liste (liste de contacts).\nLa liste démarre vide — ajoutez des contacts avec `/email/add` ou `/email/addSingle`.\n**Maximum 1 000 listes par compte** (même limite sur les trois API Mailpro et dans l'app). Renvoie HTTP 422 si la limite est atteinte.\n\n> **Alias hérité :** `/addressbook/add.{format}` — même endpoint, conservé pour rétrocompatibilité.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Title"
                ],
                "properties": {
                  "Title": {
                    "type": "string",
                    "description": "Nom d’affichage de la nouvelle liste",
                    "example": "Spring Campaign 2026"
                  },
                  "Type": {
                    "type": "integer",
                    "description": "`0` = liste standard (par défaut), `1` = liste noire",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Liste créée avec succès.\n\n> Un champ dupliqué hérité `AddressBookList` est également renvoyé (contenu identique).\n",
            "content": {
              "application/json": {
                "example": {
                  "Lists": [
                    {
                      "ListID": 103,
                      "Title": "Spring Campaign 2026",
                      "Type": 0,
                      "NumberEmails": 0,
                      "CreationDate": "2026-04-14T12:00:00"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Title manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "422": {
            "description": "Limite de listes (1 000) atteinte"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Renommer une liste",
        "description": "Met à jour le titre d’une liste existante.\nLes contacts qu’elle contient ne sont pas affectés.\n\n> **Alias hérité :** `/addressbook/edit.{format}` — même endpoint, conservé pour rétrocompatibilité.\n> Le nom de paramètre `AddressBookID` est également accepté comme alias hérité de `ListID`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "ListID",
                  "Title"
                ],
                "properties": {
                  "ListID": {
                    "type": "integer",
                    "description": "Identifiant de la liste à renommer (issu de `/list/list`). L’alias hérité `AddressBookID` est aussi accepté.",
                    "example": 101
                  },
                  "Title": {
                    "type": "string",
                    "description": "Nouveau titre de la liste",
                    "example": "Newsletter — Europe"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Liste renommée avec succès"
          },
          "400": {
            "description": "ListID ou Title manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Liste introuvable"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Supprimer une liste",
        "description": "Supprime définitivement une liste **ainsi que tous les contacts qu’elle contient**.\nCette action est irréversible.\n\n> **Alias hérité :** `/addressbook/del.{format}` — même endpoint, conservé pour rétrocompatibilité.\n> Le nom de paramètre `AddressBookID` est également accepté comme alias hérité de `ListID`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "ListID"
                ],
                "properties": {
                  "ListID": {
                    "type": "integer",
                    "description": "Identifiant de la liste à supprimer. L’alias hérité `AddressBookID` est aussi accepté.",
                    "example": 101
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Liste supprimée avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "ListID manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Liste introuvable"
          }
        }
      }
    },
    "/email/list.{format}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "listEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les contacts",
        "description": "Renvoie une liste paginée des contacts e-mail du compte.\nFiltrez par liste ou par motif d’e-mail.\nLes résultats sont triés par ordre alphabétique lorsque `sortByName=true`, sinon par ordre d’insertion.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtrer par adresse e-mail (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "name": "listId",
            "in": "query",
            "description": "Renvoyer uniquement les contacts de cette liste. L’alias hérité `addressBookId` est également accepté.",
            "schema": {
              "type": "integer"
            },
            "example": 101
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Passer à `true` pour trier les résultats par ordre alphabétique de l’adresse e-mail",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste de contacts renvoyée avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Emails": [
                    {
                      "IdEmail": 10001,
                      "Email": "alice@example.com",
                      "Field1": "Alice",
                      "Field2": "Dupont"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/email/add.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Importer des contacts (en masse)",
        "description": "Importe une ou plusieurs adresses e-mail dans une liste en une seule requête.\nFournissez les adresses dans `EmailList`, séparées par des points-virgules.\n\n**Exemple :** `alice@example.com;bob@example.com;carol@example.com`\n\nCet endpoint importe uniquement les adresses e-mail. Pour également définir des valeurs de champs personnalisés,\nutilisez plutôt `/email/addSingle` pour chaque contact.\n\nLes adresses précédemment désabonnées sont silencieusement ignorées sauf si `Force=1` est défini.\n\n**Sélection de la liste :** fournissez `ListId` (ou son alias hérité `AddressBookId`). Au moins l’un des deux est requis.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailList"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "Identifiant de la liste de destination. L’alias hérité `AddressBookId` est aussi accepté.",
                    "example": 101
                  },
                  "EmailList": {
                    "type": "string",
                    "description": "Adresses e-mail à importer, séparées par des points-virgules",
                    "example": "alice@example.com;bob@example.com;carol@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Passez à `1` pour réimporter des adresses précédemment désabonnées.\nValeur par défaut : `0` (les adresses désabonnées sont ignorées).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacts importés avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Result": "3 contacts imported"
                }
              }
            }
          },
          "400": {
            "description": "EmailList manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/email/addSingle.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addSingleEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ajouter un contact unique",
        "description": "Ajoute un contact à une liste avec des valeurs de champs personnalisés optionnelles.\n\n`Field1` à `Field25` correspondent aux définitions des colonnes personnalisées de votre liste.\nLa correspondance dépend de l’ordre dans lequel les colonnes ont été définies — consultez les paramètres\nde votre liste dans l’interface Mailpro pour savoir à quel numéro de champ correspond chaque colonne\n(par ex. Field1 = Prénom, Field2 = Nom, Field3 = Ville…).\n\n**Sélection de la liste :** fournissez `ListId` (ou son alias hérité `AddressBookId`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "Identifiant de la liste de destination. L’alias hérité `AddressBookId` est aussi accepté.",
                    "example": 101
                  },
                  "Email": {
                    "type": "string",
                    "description": "Adresse e-mail du nouveau contact",
                    "example": "alice@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Passez à `1` pour réajouter une adresse précédemment désabonnée",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Valeur du champ personnalisé 1 (la correspondance avec la colonne dépend de votre liste)",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Valeur du champ personnalisé 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Valeur du champ personnalisé 3",
                    "example": "Paris"
                  },
                  "Field4": {
                    "type": "string",
                    "description": "Valeur du champ personnalisé 4"
                  },
                  "Field5": {
                    "type": "string",
                    "description": "Valeur du champ personnalisé 5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact ajouté avec succès",
            "content": {
              "application/json": {
                "example": {
                  "EmailId": 10002,
                  "Email": "alice@example.com",
                  "Field1": "Alice",
                  "Field2": "Dupont",
                  "ListID": 101
                }
              }
            }
          },
          "400": {
            "description": "Email manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/email/edit.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "editEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Mettre à jour un contact",
        "description": "Met à jour l’adresse e-mail et/ou les valeurs des champs personnalisés d’un contact existant.\nIdentifiez le contact via `EmailId` (issu de `/email/list`).\nLes paramètres `EmailId` et `Email` sont tous deux requis.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailId",
                  "Email"
                ],
                "properties": {
                  "EmailId": {
                    "type": "integer",
                    "description": "Identifiant du contact à mettre à jour (issu de `/email/list`)",
                    "example": 10001
                  },
                  "Email": {
                    "type": "string",
                    "description": "Nouvelle adresse e-mail du contact",
                    "example": "alice.updated@example.com"
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Nouvelle valeur du champ personnalisé 1",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Nouvelle valeur du champ personnalisé 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Nouvelle valeur du champ personnalisé 3"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact mis à jour avec succès"
          },
          "400": {
            "description": "EmailId ou Email manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Contact introuvable"
          }
        }
      }
    },
    "/email/del.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "deleteEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Supprimer un contact",
        "description": "Supprime définitivement un contact à partir de son identifiant unique.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailId"
                ],
                "properties": {
                  "EmailId": {
                    "type": "integer",
                    "description": "Identifiant du contact à supprimer (issu de `/email/list`)",
                    "example": 10001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact supprimé avec succès"
          },
          "400": {
            "description": "EmailId manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Contact introuvable"
          }
        }
      }
    },
    "/message/list.{format}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les modèles de messages",
        "description": "Renvoie les modèles d’e-mails HTML enregistrés sur le compte.\nPar défaut, le corps HTML **n’est pas** inclus dans la réponse, pour limiter la taille des charges utiles.\nPassez `bodyHTML=true` pour l’inclure (limite automatiquement les résultats à 10 par page).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectFilter",
            "in": "query",
            "description": "Filtrer par objet (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Passer à `true` pour inclure le corps HTML complet dans chaque résultat.\nLorsque `true`, les résultats sont automatiquement limités à 10 par page, quelle que soit la valeur de `numberOfRecords`.\n",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Modèles de messages renvoyés avec succès",
            "content": {
              "application/json": {
                "example": {
                  "MessageList": [
                    {
                      "IDMessage": 501,
                      "Subject": "Spring Newsletter — April 2026",
                      "Language": "EN",
                      "LinkAlign": "center",
                      "LinkUp": 0,
                      "UpdateDate": "2026-03-10T14:22:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/message/add.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "addMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Créer un modèle de message",
        "description": "Crée un nouveau modèle d’e-mail HTML.\nLe modèle stocke l’objet, le corps HTML et la configuration du lien de désabonnement.\nUne fois créé, utilisez l’`IDMessage` renvoyé lors du lancement d’une campagne.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Subject",
                  "BodyHTML",
                  "Language",
                  "LinkAlign",
                  "LinkUp"
                ],
                "properties": {
                  "Subject": {
                    "type": "string",
                    "description": "Ligne d’objet de l’e-mail (255 caractères maximum)",
                    "example": "Spring Newsletter — April 2026"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenu HTML complet du corps de l’e-mail",
                    "example": "<h1>Spring is here!</h1><p>Check out our latest offers.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Code de langue pour la localisation du lien de désabonnement (par ex. `EN`, `FR`, `DE`)",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "description": "Alignement horizontal du lien de désabonnement",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "description": "Position du lien de désabonnement — `0` = en bas de l’e-mail, `1` = en haut",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modèle de message créé avec succès",
            "content": {
              "application/json": {
                "example": {
                  "IDMessage": 502,
                  "Subject": "Spring Newsletter — April 2026",
                  "Language": "EN",
                  "LinkAlign": "center",
                  "LinkUp": 0
                }
              }
            }
          },
          "400": {
            "description": "Champ requis manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/message/edit.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "editMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Mettre à jour un modèle de message",
        "description": "Met à jour le contenu et les métadonnées d’un modèle de message existant.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId",
                  "Subject",
                  "BodyHTML",
                  "Language",
                  "LinkAlign",
                  "LinkUp"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "Identifiant du modèle de message à mettre à jour (issu de `/message/list`)",
                    "example": 501
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Nouvelle ligne d’objet de l’e-mail",
                    "example": "Spring Newsletter — April 2026 (revised)"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Nouveau contenu HTML du corps de l’e-mail",
                    "example": "<h1>Spring is here!</h1><p>Updated content.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Code de langue pour la localisation du lien de désabonnement",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modèle de message mis à jour avec succès"
          },
          "400": {
            "description": "Champ requis manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Modèle de message introuvable"
          }
        }
      }
    },
    "/message/del.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "deleteMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Supprimer un modèle de message",
        "description": "Supprime définitivement un modèle de message à partir de son identifiant unique.\nLes modèles utilisés par des campagnes planifiées en attente ne peuvent pas être supprimés.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "Identifiant du modèle de message à supprimer (issu de `/message/list`)",
                    "example": 501
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modèle de message supprimé avec succès"
          },
          "400": {
            "description": "MessageId manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Modèle de message introuvable"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les campagnes planifiées",
        "description": "Renvoie la liste des campagnes e-mail planifiées et récemment traitées.\nLes résultats sont triés par date d’envoi planifiée (les plus récentes en premier).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtrer par objet de campagne (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Liste des campagnes renvoyée avec succès",
            "content": {
              "application/json": {
                "example": {
                  "sends": [
                    {
                      "IDSend": 3001,
                      "ListID": 101,
                      "SenderEmail": "newsletter@yourcompany.com",
                      "SenderName": "Your Company Newsletter",
                      "DatePlanned": "2026-04-20T09:00:00",
                      "SubjectMessage": "Spring Newsletter — April 2026",
                      "NumberCredit": 4521
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/send/campaign.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lancer une campagne",
        "description": "Planifie ou envoie immédiatement une campagne e-mail vers une liste\nà l’aide d’un modèle de message enregistré et d’une adresse expéditrice.\n\n**Requis :**\n- `IDMessage` — le modèle à envoyer (issu de `/message/list`)\n- `IDEmailExp` — l’adresse expéditrice à utiliser (issue de `/senderEmail/list`)\n- `ListId` — la liste de destinataires (issue de `/list/list`). L’alias hérité `IDAddressBook` est aussi accepté.\n\n**Planification :** définissez `DatePlanned` à une date/heure ISO 8601 future pour planifier l’envoi.\nOmettez `DatePlanned` pour envoyer immédiatement.\n\n**Suivi statistiques :** passez `Campaign=1` et fournissez un `TitleCampaign` pour activer le suivi\ndes ouvertures/clics/rebonds dans la section Statistiques.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDMessage",
                  "IDEmailExp"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "Identifiant de la liste de destinataires (issue de `/list/list`). L’alias hérité `IDAddressBook` est aussi accepté.",
                    "example": 101
                  },
                  "IDMessage": {
                    "type": "integer",
                    "description": "Identifiant du modèle de message à envoyer (issu de `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "Identifiant de l’adresse e-mail expéditrice à utiliser (issue de `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDUnsubscribeList": {
                    "type": "integer",
                    "description": "Liste utilisée pour recueillir les contacts désabonnés (liste noire).\nL’alias hérité `IDUnsubscribeAddressBook` est aussi accepté.\n",
                    "example": 102
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Date/heure d’envoi planifiées (ISO 8601). Omettre pour envoyer immédiatement.",
                    "example": "2026-04-20T09:00:00"
                  },
                  "Campaign": {
                    "type": "integer",
                    "description": "Passez à `1` pour suivre cet envoi comme campagne nommée dans les statistiques",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 1
                  },
                  "TitleCampaign": {
                    "type": "string",
                    "description": "Titre de campagne affiché dans les statistiques (requis lorsque `Campaign=1`)",
                    "example": "Spring Newsletter April 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campagne planifiée ou envoyée avec succès.\n\n> La réponse renvoie également les alias hérités `AddressBookID` et `UnsubscribeAddressBookID`\n> (identiques à `ListID` / `UnsubscribeListID`). Les nouvelles intégrations doivent les ignorer.\n",
            "content": {
              "application/json": {
                "example": {
                  "send": {
                    "IDSend": 3002,
                    "ListID": 101,
                    "UnsubscribeListID": 102,
                    "IDCampaign": 8001,
                    "SenderName": "Your Company Newsletter",
                    "SenderEmail": "newsletter@yourcompany.com",
                    "DatePlanned": "2026-04-20T09:00:00",
                    "SubjectMessage": "Spring Newsletter — April 2026",
                    "NumberCredit": 4521
                  }
                }
              }
            }
          },
          "400": {
            "description": "IDMessage ou IDEmailExp manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "403": {
            "description": "Crédits e-mail insuffisants"
          },
          "404": {
            "description": "Liste, message ou expéditeur introuvable"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "deleteCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annuler ou supprimer une campagne",
        "description": "Annule un envoi de campagne **planifié en attente**, ou supprime un envoi **terminé**.\nSeuls les envois planifiés dans le futur peuvent être annulés — les envois en cours ne peuvent pas être arrêtés.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IdSend"
                ],
                "properties": {
                  "IdSend": {
                    "type": "integer",
                    "description": "Identifiant de l’envoi de campagne à annuler ou supprimer (issu de `/send/list`)",
                    "example": 3001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campagne annulée ou supprimée avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Campaign Deleted"
                }
              }
            }
          },
          "400": {
            "description": "IdSend manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Campagne introuvable"
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listScheduledCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister mes campagnes e-mail planifiées",
        "description": "Renvoie les campagnes e-mail et les envois unitaires planifiés à une date future et qui\nn’ont pas encore été distribués. Utile avant un appel à `/cancel` ou `/reschedule`.\nLes enregistrements sont triés par `DatePlanned` croissant.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Liste des campagnes/envois planifiés.\n\n> Chaque enregistrement inclut également les alias hérités `AddressBookID` et\n> `UnsubscribeAddressBookID` (identiques à `ListID` / `UnsubscribeListID`).\n",
            "content": {
              "application/json": {
                "example": {
                  "sends": [
                    {
                      "IDSend": 5001,
                      "ListID": 101,
                      "UnsubscribeListID": 102,
                      "IDCampaign": 8001,
                      "SenderName": "Your Company Newsletter",
                      "SenderEmail": "newsletter@yourcompany.com",
                      "DatePlanned": "2026-05-01T09:00:00",
                      "SubjectMessage": "Spring Sale 2026",
                      "NumberCredit": 4521
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/send/{IdSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "cancelScheduledCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annuler une campagne/un envoi planifié",
        "description": "Annule un envoi e-mail planifié (campagne ou unitaire) qui n’a pas encore été distribué.\nSi l’envoi est déjà parti (ou s’il n’existe pas / appartient à un autre client),\nrenvoie **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Envoi annulé",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 5001
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "409": {
            "description": "Déjà distribué ou introuvable"
          }
        }
      }
    },
    "/send/{IdSend}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "rescheduleCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Replanifier une campagne/un envoi planifié",
        "description": "Met à jour la `DatePlanned` d’un envoi e-mail planifié. La nouvelle date doit être\n**dans le futur** et **dans un délai de 90 jours**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "PlanDate"
                ],
                "properties": {
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "example": "2026-12-31T14:30:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envoi replanifié",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSend": 5001,
                  "NewPlanDate": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "PlanDate manquante ou invalide"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "409": {
            "description": "Déjà distribué, introuvable ou nouvelle date hors plage (doit être future et dans un délai de 90 jours)"
          }
        }
      }
    },
    "/send/mail/scheduled.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "listScheduledMails",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les e-mails unitaires programmés",
        "description": "Renvoie les e-mails unitaires envoyés avec `/send/sendmail` et une date future, pas encore partis. Les campagnes sont listées par `/send/scheduled`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "E-mails programmés renvoyés",
            "content": {
              "application/json": {
                "example": {
                  "scheduledMails": [
                    {
                      "IdSingleSend": 880123,
                      "Email": "jane@example.com",
                      "Subject": "Your invoice",
                      "DatePlanned": "2026-12-01T09:00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "cancelMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annuler un e-mail unitaire programmé",
        "description": "Annule l'e-mail tant qu'il n'est pas parti.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` renvoyé par `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "E-mail annulé",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 880123
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "409": {
            "description": "Envoi introuvable, ou déjà parti"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/reschedule.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "rescheduleMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reprogrammer un e-mail unitaire programmé",
        "description": "Change la date d'envoi. La nouvelle date doit être future et à moins de 90 jours. `PATCH` est aussi accepté.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` renvoyé par `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "PlanDate"
                ],
                "properties": {
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Nouvelle date d'envoi (ISO 8601)",
                    "example": "2026-12-15T09:00:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "E-mail reprogrammé",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSingleSend": 880123,
                  "NewPlanDate": "2026-12-15T09:00:00"
                }
              }
            }
          },
          "400": {
            "description": "Date manquante ou invalide"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "409": {
            "description": "Envoi introuvable, déjà parti, ou date hors limites"
          }
        }
      }
    },
    "/send/sendingTest.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendTestEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Envoyer un e-mail de test",
        "description": "Envoie un aperçu d’un modèle de message à un destinataire spécifié pour relecture\navant le lancement de la véritable campagne.\nL’expéditeur, le modèle et le destinataire de test sont tous identifiés par leurs identifiants.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId",
                  "IDEmailExpFrom",
                  "IDEmailExpTo"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "Identifiant du modèle de message à prévisualiser (issu de `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExpFrom": {
                    "type": "integer",
                    "description": "Identifiant de l’adresse expéditrice à utiliser (issue de `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDEmailExpTo": {
                    "type": "integer",
                    "description": "Identifiant de l’adresse expéditrice destinataire — l’e-mail de test est envoyé à cette adresse",
                    "example": 202
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "E-mail de test envoyé avec succès",
            "content": {
              "application/json": {
                "example": {
                  "SendingTest": {
                    "IdSendingTest": 7001,
                    "ToEmail": "test@yourcompany.com",
                    "FromEmail": "newsletter@yourcompany.com",
                    "SenderName": "Your Company Newsletter"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Champ requis manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/send/sendmail.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "sendTransactionalEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Envoyer un e-mail transactionnel",
        "description": "Envoie un e-mail transactionnel ponctuel à un ou plusieurs destinataires.\nContrairement aux campagnes, cet endpoint ne nécessite pas de liste —\nl’adresse du destinataire et le corps HTML sont transmis directement.\n\n**Requis :**\n- `IDEmailExp` — l’identifiant de l’adresse expéditrice (issu de `/senderEmail/list`)\n- `EmailData` — destinataire au format `email,field1,field2,...,field25` (séparés par des virgules)\n- `BodyHTML` — le corps HTML\n- `Subject` — la ligne d’objet\n\n**Format `EmailData` :** `alice@example.com,Alice,Dupont,Paris`\nLa première valeur est l’adresse e-mail ; les valeurs 2 à 26 correspondent à Field1–Field25 pour\nles variables de personnalisation de votre modèle HTML.\n\n**Plusieurs destinataires :** séparez plusieurs entrées `EmailData` par des points-virgules :\n`alice@example.com,Alice;bob@example.com,Bob`\n\n**Planification :** définissez `DatePlanned` à une date/heure ISO 8601 future, ou omettez-la pour envoyer immédiatement.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "Identifiant de l’adresse e-mail expéditrice à utiliser (issue de `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinataire au format `email,champ1,champ2,...,champ25` (séparés par des virgules).\nLa première valeur est l'adresse email ; les suivantes sont des champs de\npersonnalisation mappés sur Field1–Field25 dans votre modèle HTML.\n\n**La partie locale** de l'email (avant le `@`) accepte les lettres, les chiffres et\n`. _ - +` — y compris le sous-adressage RFC 5322 (`user+tag@domain`, ex. Gmail,\nFastmail, Proton). Les autres caractères spéciaux autorisés par la RFC 5322\n(ex. `! # $ % & ' * / = ? ^ { | } ~`) et les parties locales entre guillemets ne\nsont **pas** acceptés.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenu HTML complet du corps de l’e-mail",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Ligne d’objet de l’e-mail (255 caractères maximum)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "array",
                    "maxItems": 5,
                    "description": "Pièces jointes optionnelles — envoyez la requête en `multipart/form-data` et ajoutez une partie fichier par pièce jointe (n'importe quel nom de champ). Jusqu'à **5 fichiers**, **10 Mo par fichier**, **15 Mo au total**. Types acceptés : PDF, Word, Excel, PowerPoint, images (JPG, PNG, GIF, WebP), ZIP, CSV, TXT — les fichiers exécutables et scripts sont refusés. **Facturation :** l'envoi garde son crédit habituel, plus **1 crédit par 512 Ko de pièces jointes au-delà des 512 premiers Ko** (les pièces jointes ≤ 512 Ko n'ajoutent rien). Tous les autres champs de cet endpoint (`ReplyTo`, `ActivateStatistics`, `CustomHeaders`, …) fonctionnent exactement comme dans la variante form-urlencoded.",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (par défaut) : les pièces jointes ne servent qu'à cet envoi — elles sont stockées hors de\nvotre compte, ne comptent pas dans votre quota de stockage et sont supprimées automatiquement après\n35 jours. `true` : les pièces jointes sont aussi conservées dans les fichiers de votre compte (dossier\n`Secure/Files/Sending/api`) et comptent dans votre quota de stockage.\n",
                    "example": false
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "Identifiant de l’adresse e-mail expéditrice à utiliser (issue de `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinataire au format `email,champ1,champ2,...,champ25` (séparés par des virgules).\nLa première valeur est l'adresse email ; les suivantes sont des champs de\npersonnalisation mappés sur Field1–Field25 dans votre modèle HTML.\n\n**La partie locale** de l'email (avant le `@`) accepte les lettres, les chiffres et\n`. _ - +` — y compris le sous-adressage RFC 5322 (`user+tag@domain`, ex. Gmail,\nFastmail, Proton). Les autres caractères spéciaux autorisés par la RFC 5322\n(ex. `! # $ % & ' * / = ? ^ { | } ~`) et les parties locales entre guillemets ne\nsont **pas** acceptés.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenu HTML complet du corps de l’e-mail",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Ligne d’objet de l’e-mail (255 caractères maximum)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "string",
                    "description": "Pièces jointes optionnelles sous forme de **tableau JSON** d'objets `{ \"filename\": …, \"content\": … }`, avec `content` **encodé en Base64** (même format que l'API CRM v3). Jusqu'à **5 fichiers**, **10 MB par fichier** et **15 MB au total** (après décodage). Les formats courants de documents et d'images sont acceptés ; les fichiers exécutables et scripts sont refusés. **Facturation :** l'envoi conserve son crédit habituel, plus **1 crédit par 512 KB de pièces jointes au-delà des premiers 512 KB**. *Vous pouvez aussi envoyer les fichiers en parties `multipart/form-data` (voir le corps de requête multipart ci-dessus) — les deux fonctionnent.*",
                    "example": "[{\"filename\":\"invoice.pdf\",\"content\":\"JVBERi0xLjQK...\"}]"
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (par défaut) : les pièces jointes ne servent qu'à cet envoi — elles sont stockées hors de\nvotre compte, ne comptent pas dans votre quota de stockage et sont supprimées automatiquement après\n35 jours. `true` : les pièces jointes sont aussi conservées dans les fichiers de votre compte (dossier\n`Secure/Files/Sending/api`) et comptent dans votre quota de stockage.\n",
                    "example": false
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Date/heure d’envoi planifiées (ISO 8601). Omettre pour envoyer immédiatement.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "ActivateStatistics": {
                    "type": "boolean",
                    "description": "Passez à `true` pour suivre les ouvertures et les clics de cet e-mail",
                    "default": false,
                    "example": true
                  },
                  "ReplyTo": {
                    "type": "string",
                    "description": "Adresse e-mail de réponse. Si omise, les réponses sont envoyées à l’adresse expéditrice.",
                    "example": "support@yourcompany.com"
                  },
                  "UnsubscriptionLink": {
                    "type": "boolean",
                    "description": "Passez à `true` pour ajouter un lien de désabonnement au corps de l’e-mail",
                    "default": false,
                    "example": false
                  },
                  "CustomHeaders": {
                    "type": "string",
                    "description": "En-têtes SMTP supplémentaires, sous forme de chaîne `key=value` séparée par des points-virgules",
                    "example": "X-Campaign-ID=campaign_42;X-Priority=1"
                  },
                  "BodyText": {
                    "type": "string",
                    "description": "Solution de repli en texte brut pour les clients de messagerie qui n’affichent pas le HTML",
                    "example": "Hello Alice, your order has been confirmed."
                  },
                  "List_Unsubscribe": {
                    "type": "string",
                    "description": "Valeur de l’en-tête e-mail `List-Unsubscribe` (URL ou mailto)",
                    "example": "https://yourcompany.com/unsubscribe?token=abc123"
                  },
                  "List_Unsubscribe_Post": {
                    "type": "string",
                    "description": "Valeur de l’en-tête `List-Unsubscribe-Post` (RFC 8058)",
                    "example": "List-Unsubscribe=One-Click"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "E-mail transactionnel envoyé ou planifié avec succès",
            "content": {
              "application/json": {
                "example": {
                  "SingleSend": {
                    "IdSingleSend": 8001,
                    "IdEmailExp": 201,
                    "DatePlanned": "2026-04-15T14:30:00",
                    "Subject": "Your order #12345 is confirmed",
                    "Email": "alice@example.com",
                    "Field1": "Alice",
                    "Field2": "Dupont",
                    "UnsubscriptionLink": false,
                    "ActivateStatistics": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Champ requis manquant ou format d’e-mail invalide"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "403": {
            "description": "Crédits e-mail insuffisants"
          },
          "404": {
            "description": "Expéditeur introuvable ou adresse e-mail désabonnée"
          }
        }
      }
    },
    "/send/{IdSend}/status.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "getTransactionalStatus",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtenir le statut de livraison d'un e-mail transactionnel",
        "description": "Renvoie le statut de livraison actuel d'un e-mail transactionnel envoyé via `/send/sendmail`. Transmettez l'`IdSingleSend` renvoyé par cet appel.\n\nValeurs possibles : `delivered` (accepté par le serveur du destinataire, voir `DiagCode`), `bounced` (refusé — `BounceType: hard` adresse invalide ou refus définitif, `soft` refus après nouvelles tentatives), `sent` (remis au serveur de messagerie, pas encore de réponse), `scheduled` (pas encore envoyé, `DatePlanned` dans le futur) et `queued` (en attente d'expédition). `delivered` et `bounced` sont finaux : arrêtez d'interroger. Chaque e-mail a un statut final au plus tard 48 heures après l'envoi ; interrogez toutes les 15 minutes au plus (chaque appel compte dans votre quota API) ou utilisez les webhooks `email.delivered` / `email.bounced`. Seul le client qui a envoyé l'e-mail peut lire son statut — tout autre id renvoie 404.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "description": "L'`IdSingleSend` renvoyé par `/send/sendmail`.",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Statut de livraison actuel",
            "content": {
              "application/json": {
                "example": {
                  "status": {
                    "IdSingleSend": 8001,
                    "Email": "alice@example.com",
                    "Status": "delivered",
                    "DatePlanned": "2026-04-15T14:30:00",
                    "StatusDate": "2026-04-15T14:30:07",
                    "DiagCode": "2.0.0 (success)",
                    "BounceType": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Aucun envoi transactionnel trouvé avec cet id pour ce client"
          }
        }
      }
    },
    "/senderEmail/list.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "listSenderEmails",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les adresses expéditrices validées",
        "description": "Renvoie la liste des adresses d'expéditeur configurées pour le compte.\nSeules les adresses avec `IsValid: true` peuvent être utilisées pour envoyer des campagnes.\nLes nouvelles adresses s'ajoutent avec `/senderEmail/add` et deviennent valides une fois le lien de l'e-mail de validation cliqué.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtrer par adresse e-mail (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "@yourcompany.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Passer à `true` pour trier les résultats par ordre alphabétique du nom d’expéditeur",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Adresses expéditrices renvoyées avec succès",
            "content": {
              "application/json": {
                "example": {
                  "ExpEmailList": [
                    {
                      "IDEmailExp": 201,
                      "Email": "newsletter@yourcompany.com",
                      "SenderName": "Your Company Newsletter",
                      "IsValid": true,
                      "CreationDate": "2025-06-01T09:00:00"
                    },
                    {
                      "IDEmailExp": 202,
                      "Email": "support@yourcompany.com",
                      "SenderName": "Your Company Support",
                      "IsValid": true,
                      "CreationDate": "2025-06-01T09:05:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/senderEmail/add.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "addSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ajouter une adresse d'expéditeur",
        "description": "Ajoute l'adresse avec les mêmes contrôles que l'application et lui envoie un e-mail de validation. Elle est utilisable une fois le lien de cet e-mail cliqué. Un compte peut avoir jusqu'à 25 expéditeurs, validés ou en attente.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email",
                  "SenderName"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Adresse de l'expéditeur",
                    "example": "news@example.com"
                  },
                  "SenderName": {
                    "type": "string",
                    "description": "Nom affiché aux destinataires",
                    "example": "Example News"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Adresse ajoutée. `DomainHasMx` vaut false quand le domaine n'a pas d'enregistrement MX.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true,
                  "DomainHasMx": true
                }
              }
            }
          },
          "400": {
            "description": "`Email` ou `SenderName` manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "422": {
            "description": "Adresse refusée : invalide, déjà parmi les expéditeurs du compte, domaine de messagerie public, nom interdit, ou limite de 25 atteinte. Le message donne la raison."
          },
          "503": {
            "description": "Indisponible pour le moment, réessayez"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/resendValidation.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "resendSenderValidation",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Renvoyer l'e-mail de validation",
        "description": "Pour une adresse encore en attente de validation.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID de l'expéditeur, de `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "E-mail renvoyé",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Expéditeur introuvable"
          },
          "409": {
            "description": "Cet expéditeur est déjà validé"
          },
          "503": {
            "description": "Indisponible pour le moment, réessayez"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/authentication.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "getSenderAuthentication",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Contrôler le domaine d'un expéditeur (SPF, DKIM, DMARC, MX)",
        "description": "Contrôle le domaine en direct dans le DNS et renvoie les enregistrements à publier. Lecture seule. Le DKIM s'active dans l'application : `DkimSettingsUrl` ouvre le bon écran.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID de l'expéditeur, de `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "État du domaine. `Spf.RecommendedRecord` est construit à partir de votre enregistrement actuel : publiez-le seulement si `Spf.ChangeNeeded` vaut true.",
            "content": {
              "application/json": {
                "example": {
                  "Domain": "example.com",
                  "Spf": {
                    "Valid": true,
                    "Record": "v=spf1 include:spf.mailpro.com -all",
                    "RecommendedRecord": "v=spf1 include:spf.mailpro.com -all",
                    "ChangeNeeded": false
                  },
                  "Dkim": {
                    "Valid": true,
                    "Records": [
                      {
                        "Host": "key._domainkey.example.com",
                        "Value": "v=DKIM1;k=rsa;p=MIIBIjANBgkq...",
                        "Validated": true
                      }
                    ]
                  },
                  "Dmarc": {
                    "Valid": true,
                    "Record": "v=DMARC1; p=quarantine"
                  },
                  "Mx": {
                    "Valid": true,
                    "Record": "mail.example.com"
                  },
                  "DkimSettingsUrl": "https://app.mailpro.com/dkim/list?d=example.com"
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Expéditeur introuvable"
          },
          "503": {
            "description": "Indisponible pour le moment, réessayez"
          }
        }
      }
    },
    "/senderEmail/del.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "deleteSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Retirer une adresse expéditrice",
        "description": "Retire une adresse e-mail expéditrice validée du compte.\nLes adresses expéditrices utilisées par des campagnes planifiées ne peuvent pas être supprimées.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "idEmailExp"
                ],
                "properties": {
                  "idEmailExp": {
                    "type": "integer",
                    "description": "Identifiant de l’adresse expéditrice à retirer (issu de `/senderEmail/list`)",
                    "example": 201
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Adresse expéditrice retirée avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Result": "EmailSender Deleted"
                }
              }
            }
          },
          "400": {
            "description": "idEmailExp manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/list.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "listStats",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les statistiques de campagnes",
        "description": "Renvoie les indicateurs de performance globaux de toutes les campagnes : nombre d’envois,\ntaux d’ouverture, taux de clic, nombre de rebonds. Filtrez par plage de dates ou par titre de campagne.\nLes résultats sont triés par date d’envoi (les plus récents en premier).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleCampaignFilter",
            "in": "query",
            "description": "Filtrer par titre de campagne (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "spring"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "dateStart",
            "in": "query",
            "description": "Début de la plage de dates du filtre (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-01-01T00:00:00"
          },
          {
            "name": "dateEnd",
            "in": "query",
            "description": "Fin de la plage de dates du filtre (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-12-31T23:59:59"
          }
        ],
        "responses": {
          "200": {
            "description": "Statistiques de campagnes renvoyées avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Campaigns": [
                    {
                      "IdCampaign": 8001,
                      "DateCampaign": "2026-04-20T09:00:01",
                      "TitleCampaign": "Spring Newsletter April 2026",
                      "NumberEmailSend": 4521,
                      "NumberEmailOpen": 1823,
                      "NumberEmailClick": 342,
                      "BadMail": 12,
                      "NumberUnsubscribers": 8,
                      "NumberComplaints": 1,
                      "SpamTrap": 0,
                      "DeliverabilityScore": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/byHour.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByHour",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Statistiques par heure",
        "description": "Renvoie la ventilation horaire des ouvertures et des clics pour une campagne donnée.\nUtile pour identifier l’heure d’envoi optimale.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "Identifiant de la campagne (issu de `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Statistiques horaires renvoyées avec succès",
            "content": {
              "application/json": {
                "example": {
                  "ByHour": [
                    {
                      "Hour": 9,
                      "Opens": 823,
                      "Clicks": 142
                    },
                    {
                      "Hour": 10,
                      "Opens": 512,
                      "Clicks": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/byDay.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByDay",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Statistiques par jour",
        "description": "Renvoie la ventilation journalière des ouvertures et des clics pour une campagne donnée.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "Identifiant de la campagne (issu de `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Statistiques journalières renvoyées avec succès"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/del.{format}": {
      "post": {
        "tags": [
          "Statistics"
        ],
        "operationId": "deleteStats",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Supprimer les statistiques d’une campagne",
        "description": "Supprime définitivement tous les enregistrements statistiques d’une campagne donnée.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IdCampaign"
                ],
                "properties": {
                  "IdCampaign": {
                    "type": "integer",
                    "description": "Identifiant de la campagne dont supprimer les statistiques (issu de `/stats/list`)",
                    "example": 8001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Statistiques de campagne supprimées avec succès",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Statistic Deleted"
                }
              }
            }
          },
          "400": {
            "description": "IdCampaign manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Campagne introuvable"
          }
        }
      }
    },
    "/stats/country.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsCountry",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ventilation par géolocalisation",
        "description": "Renvoie la ventilation par géolocalisation des ouvertures de campagne — combien\nd’ouvertures proviennent de chaque pays.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Ventilation par pays renvoyée"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/open.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsOpens",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Journal des événements d’ouverture",
        "description": "Renvoie le journal des événements d’ouverture par destinataire pour une campagne (une ligne par ouverture).\nUtilisez `emailFilter` pour rechercher un destinataire spécifique (correspondance partielle, insensible à la casse).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "name": "emailFilter",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Événements d’ouverture renvoyés"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/click.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsClicks",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Journal des événements de clic",
        "description": "Renvoie le journal des événements de clic par destinataire pour une campagne — en précisant\nle lien cliqué et le moment du clic.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "name": "emailFilter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Événements de clic renvoyés"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/system.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsSystem",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ventilation par système d’exploitation",
        "description": "Renvoie la ventilation des ouvertures par système d’exploitation (Windows, macOS, iOS,\nAndroid, Linux, etc.) pour une campagne donnée.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Ventilation par OS renvoyée"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/emailSoftware.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsEmailSoftware",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ventilation par client de messagerie",
        "description": "Renvoie la ventilation des ouvertures par client de messagerie (Gmail, Outlook, Apple Mail,\nThunderbird, etc.) pour une campagne donnée.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Ventilation par client de messagerie renvoyée"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/stats/bounce.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsBounce",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Journal des rebonds",
        "description": "Renvoie la liste des destinataires en rebond (rebonds durs, rebonds doux,\nplaintes pour spam) d'une campagne, avec la raison de l'échec pour chaque adresse.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "name": "emailFilter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Événements de rebond renvoyés",
            "content": {
              "application/json": {
                "example": {
                  "ListBadMail": [
                    {
                      "Email": "bounce@example.com",
                      "Date": "2026-04-20T09:05:12",
                      "Error": "550 5.1.1 recipient rejected",
                      "AddressbookId": 1813318
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/suppression/bounces.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listBounces",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les bounces du compte",
        "description": "Les plus récents d'abord. Le total est dans l'en-tête `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`hard` ou `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origine du bounce : `list`, `contact`, `api` ou `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Adresse exacte",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "À partir de cette date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Jusqu'à cette date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bounces renvoyés",
            "content": {
              "application/json": {
                "example": {
                  "bounces": [
                    {
                      "Id": 5521,
                      "Source": "contact",
                      "BounceType": "hard",
                      "Email": "old@example.com",
                      "Date": "2026-10-12T08:30:00",
                      "DiagCode": "550 5.1.1 User unknown",
                      "IdList": 101
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`type` doit valoir `hard` ou `soft`"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Retirer un bounce",
        "description": "`Source` et `Type` sont obligatoires, tels que renvoyés par `/suppression/bounces` : un `Id` seul n'est pas unique.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` du bounce",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Source",
                  "Type"
                ],
                "properties": {
                  "Source": {
                    "type": "string",
                    "description": "`list`, `contact`, `api` ou `smtp`"
                  },
                  "Type": {
                    "type": "string",
                    "enum": [
                      "hard",
                      "soft"
                    ],
                    "description": "`hard` ou `soft`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bounce retiré",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": false
                }
              }
            }
          },
          "400": {
            "description": "`Source` ou `Type` manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Bounce introuvable"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/restore.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "restoreBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remettre en liste un contact en hard bounce",
        "description": "Uniquement pour un hard bounce de source `contact`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` du bounce",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contact remis en liste",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": true
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Hard bounce de contact introuvable, ou adresse plus active"
          }
        }
      }
    },
    "/suppression/unsubscribers.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister les désinscrits du compte",
        "description": "Les plus récents d'abord. Le total est dans l'en-tête `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origine de la désinscription : `contact`, `list`, `smtp`, `api` ou `api3`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Adresse exacte",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "À partir de cette date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Jusqu'à cette date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Désinscrits renvoyés",
            "content": {
              "application/json": {
                "example": {
                  "unsubscribers": [
                    {
                      "Id": 9012,
                      "Source": "api",
                      "Email": "stop@example.com",
                      "Date": "2026-10-20T16:05:00",
                      "ListName": null,
                      "Comment": "Asked by phone"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/suppression/unsubscribers/add.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "addUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ajouter un désinscrit",
        "description": "Sans `ListId`, l'adresse est désinscrite pour tout le compte. Avec, de cette liste de désinscription seulement.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Adresse à désinscrire",
                    "example": "stop@example.com"
                  },
                  "Comment": {
                    "type": "string",
                    "description": "Commentaire libre",
                    "example": "Asked by phone"
                  },
                  "ListId": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Liste de désinscription du compte (facultatif)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "C'est fait. `AlreadyUnsubscribed` vaut true quand l'adresse l'était déjà.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "AlreadyUnsubscribed": false
                }
              }
            }
          },
          "400": {
            "description": "Une adresse valide est obligatoire"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "`ListId` n'est pas une liste de désinscription de ce compte"
          }
        }
      }
    },
    "/suppression/unsubscribers/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Retirer un désinscrit",
        "description": "`Source` est obligatoire, tel que renvoyé par `/suppression/unsubscribers` : un `Id` seul n'est pas unique.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` du désinscrit",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Source"
                ],
                "properties": {
                  "Source": {
                    "type": "string",
                    "description": "`contact`, `list`, `smtp`, `api` ou `api3`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Désinscrit retiré",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Removed": 9012
                }
              }
            }
          },
          "400": {
            "description": "`Source` est obligatoire"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "404": {
            "description": "Désinscrit introuvable"
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listHistory",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lister l’historique des envois",
        "description": "Renvoie un journal paginé de tous les envois d’e-mails passés.\nFiltrez par identifiant de campagne ou par objet.\nPassez `bodyHTML=true` pour inclure le corps HTML (limite automatiquement à 10 par page).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtrer par objet de campagne (correspondance partielle, insensible à la casse)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "description": "Renvoyer l’historique d’une campagne spécifique uniquement",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Passer à `true` pour inclure le corps HTML complet.\nLimite automatiquement les résultats à 10 par page.\n",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Historique renvoyé avec succès",
            "content": {
              "application/json": {
                "example": {
                  "HistoricList": [
                    {
                      "IDHistoric": 9001,
                      "SubjectMessage": "Spring Newsletter — April 2026",
                      "DateSend": "2026-04-20T09:00:01",
                      "NumberSend": 4521,
                      "NumberOpen": 1823,
                      "NumberClick": 342
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Téléverser un fichier de contacts (CSV/XLSX) pour import en masse",
        "description": "Téléversez un fichier CSV ou XLSX pour importer des contacts e-mail dans une liste.\nLe fichier est stocké et placé en file d’attente pour un traitement asynchrone — l’endpoint\nrenvoie immédiatement un `ImportJobId`.\n\n**Type de requête :** `multipart/form-data`\n\n**Champs de formulaire requis :**\n- `IdClient` (entier) — votre identifiant client Mailpro\n- `ApiKey` (chaîne) — votre clé API\n- `ListId` (entier) — identifiant de la liste cible. L’alias hérité `AddressBookId` est aussi accepté.\n- `file` (binaire) — le fichier CSV ou XLSX à téléverser\n\n**Optionnel :**\n- `WebhookUrl` (chaîne) — URL HTTPS appelée lorsque le traitement est terminé.\n  Reçoit une charge utile JSON avec le statut final (success/failed) et\n  le nombre de lignes importées/ignorées/invalides.\n\n**Format du fichier :**\n- Encodage UTF-8\n- Première ligne = en-têtes (l’un d’eux doit être `Email` — insensible à la casse)\n- Les autres colonnes correspondent aux champs personnalisés de la liste de destination\n- Taille maximale du fichier : 50 Mo\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "ListId",
                  "file"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "Identifiant de la liste de destination. L’alias hérité `AddressBookId` est aussi accepté.",
                    "example": 101
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Fichier CSV ou XLSX (UTF-8, 50 Mo maximum)"
                  },
                  "WebhookUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL de callback invoquée lorsque le traitement est terminé",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fichier accepté et mis en file d’attente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 13,
                  "InternalName": "230575-20260420140221-contacts.csv"
                }
              }
            }
          },
          "400": {
            "description": "Aucun fichier téléversé ou ListId manquant"
          },
          "401": {
            "description": "Identifiants invalides"
          },
          "500": {
            "description": "Erreur de serveur ou de stockage"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Service de gestion des webhooks (distinct de l’hôte de l’API principale)"
        }
      ],
      "get": {
        "summary": "Lister les webhooks",
        "description": "Renvoie l’ensemble des webhooks configurés sur le compte authentifié.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Tableau des webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "items": [
                    {
                      "id": 14,
                      "url": "https://example.com/hooks/mailpro",
                      "description": "Intégration Slack",
                      "is_active": true,
                      "created_at": "2026-07-01T21:09:52.43",
                      "updated_at": "2026-07-21T18:56:08.02",
                      "last_delivery_at": "2026-07-21T18:56:07.653",
                      "last_delivery_status": 200,
                      "consecutive_failures": 0,
                      "events": [
                        "email.delivered",
                        "email.bounced"
                      ]
                    }
                  ],
                  "total": 1
                }
              }
            }
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      },
      "post": {
        "summary": "Créer un webhook",
        "description": "Crée un nouvel abonnement webhook. La réponse contient un `secret` qui\nn’est **affiché qu’une seule fois** — stockez-le immédiatement, côté serveur. Utilisez-le pour\nvérifier la signature HMAC de chaque charge utile entrante.\n\n**Limites** : 20 webhooks maximum par compte, 50 événements maximum par webhook.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              },
              "example": {
                "url": "https://example.com/hooks/mailpro",
                "events": [
                  "email.delivered",
                  "email.bounced"
                ],
                "description": "Intégration Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook créé — le `secret` n’est renvoyé qu’ici",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "email.delivered",
                    "email.bounced"
                  ],
                  "description": "Intégration Slack",
                  "isActive": true,
                  "consecutiveFailures": 0,
                  "autoDisabledAt": null,
                  "autoDisabledReason": null,
                  "createdAt": "2026-05-25T10:00:00Z",
                  "updatedAt": "2026-05-25T10:00:00Z",
                  "secret": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
                }
              }
            }
          },
          "400": {
            "description": "URL, liste d’événements invalide ou limite dépassée"
          },
          "401": {
            "description": "Identifiants invalides"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Service de gestion des webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "summary": "Récupérer un webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Le webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "404": {
            "description": "Webhook introuvable"
          }
        }
      },
      "put": {
        "summary": "Mettre à jour un webhook",
        "description": "Mise à jour partielle — seuls les champs transmis sont modifiés.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook mis à jour",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "Charge utile invalide"
          },
          "404": {
            "description": "Webhook introuvable"
          }
        }
      },
      "delete": {
        "summary": "Supprimer un webhook",
        "description": "Supprime définitivement le webhook et l’intégralité de son historique de livraisons.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Supprimé"
          },
          "404": {
            "description": "Webhook introuvable"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Service de gestion des webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Envoyer un événement de test",
        "description": "Met en file d’attente un événement `ping` immédiat (ou tout autre type d’événement via le\nchamp de corps `eventType`) à destination de votre endpoint. Utile pour vérifier l’accessibilité\net la vérification de signature avant de s’appuyer sur de vrais événements.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventType": {
                    "type": "string",
                    "default": "ping"
                  }
                }
              },
              "example": {
                "eventType": "ping"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Événement mis en file d’attente pour distribution",
            "content": {
              "application/json": {
                "example": {
                  "deliveryId": 1234,
                  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
                  "eventType": "ping"
                }
              }
            }
          },
          "404": {
            "description": "Webhook introuvable"
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Service de gestion des webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Faire pivoter le secret HMAC",
        "description": "Génère un nouveau secret HMAC et invalide immédiatement l’ancien.\nLe nouveau secret est renvoyé **une seule fois** dans la réponse — stockez-le. Chaque\nlivraison ultérieure sera signée avec le nouveau secret.\n\nUtilisez cette opération si vous soupçonnez que votre secret a été compromis.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Nouveau secret (visible une seule fois)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
                }
              }
            }
          },
          "404": {
            "description": "Webhook introuvable"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Service de gestion des webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "in": "query",
          "name": "limit",
          "schema": {
            "type": "integer",
            "default": 50,
            "maximum": 200
          }
        },
        {
          "in": "query",
          "name": "cursor",
          "schema": {
            "type": "integer",
            "format": "int64"
          },
          "description": "Curseur de pagination (= dernier identifiant de livraison vu). Renvoie les livraisons avec `id < cursor`."
        }
      ],
      "get": {
        "summary": "Lister les tentatives de livraison",
        "description": "Renvoie l’historique des tentatives de distribution pour ce webhook (rétention 30 jours).\nUtile pour le débogage — quels événements ont été envoyés, codes de statut reçus,\nnombre de réessais, messages d’erreur.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Tableau des tentatives de livraison (les plus récentes en premier)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook introuvable"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Service de gestion des webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "in": "path",
          "name": "deliveryId",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Rejouer une livraison",
        "description": "Met en file d’attente une nouvelle tentative de livraison avec la même charge utile que l’originale.\nUtile pour redéclencher une livraison ayant échoué après correction de votre endpoint.\nUne NOUVELLE ligne `Webhook_Delivery` est créée (l’originale est préservée\npour audit). Le rejouage suit la politique de réessai standard\n(même calendrier de backoff, même règle de désactivation automatique après 10 échecs).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Rejouage mis en file d’attente",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook ou livraison introuvable"
          }
        }
      }
    }
  }
}