{
  "openapi": "3.0.3",
  "info": {
    "title": "Mailpro™ Email API v2",
    "version": "2",
    "description": "The Mailpro™ Email API v2 lets you programmatically manage contact lists, email\ntemplates, sender addresses, and campaigns — and send both bulk and transactional emails.\n\n## Authentication\n\nEvery endpoint accepts **three authentication methods**. Use whichever fits\nyour stack.\n\n- **OAuth 2.0** — scoped, revocable tokens for third-party apps and\n  integration platforms (Zapier, Make, n8n). The only method you can hand to\n  a third party. **OAuth tokens are scope-gated per endpoint** (see below).\n- **Bearer JWT** (legacy) — an HMAC token from `POST /token`, not scoped.\n- **IdClient + ApiKey** (legacy) — client ID + API key.\n\n> Legacy Bearer JWT and IdClient+ApiKey keep working unchanged and are **not**\n> scope-gated. Only OAuth 2.0 access tokens are subject to the per-endpoint\n> scope checks shown on each operation below.\n\n### Method 1 — OAuth 2.0 (recommended for integrations)\n\nMailpro runs **one** OAuth 2.0 authorization server for all of its APIs, at a\nsingle version-neutral surface: **`https://api.mailpro.com/oauth/`**. There is\nno per-version OAuth endpoint — you obtain a token from `/oauth/token` and the\n**same** token works on this Email v2 API, on CRM v3 and on SMS. Which\nendpoints it may call is governed by the token's **scopes**, not the API base\nURL. Issuer (`iss` claim): `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Authorize | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / Refresh | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Discovery | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nGrants: `authorization_code` **+ PKCE (S256, mandatory)**, `client_credentials`,\n`refresh_token` (rotation). Access-token TTL **20 min**; refresh token **30 days**\n(sliding, single-use); auth code **60 s**.\n\n**Quickstart — get a token and call this API** (replace placeholders; never\ncommit a real 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\nThen call this API with `Authorization: Bearer ACCESS_TOKEN`. The same token\nworks on the CRM v3 and SMS APIs. A token missing an endpoint's required\nscope gets **403 `insufficient_scope`**. Full flow walk-through and scope\ncatalog: see the **CRM v3** API docs › Authentication. Email-relevant scopes:\n`email:send`, `email:read`, `email:templates:read`, `email:templates:write`,\n`contacts:read`, `contacts:write`, `account:read`.\n\n### Method 2 — Bearer JWT (legacy)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nGet a token via `POST /token` (form-encoded, 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\nThe same token is also valid on the CRM API v3 and the SMS API —\nauthenticate once, call any API. Tokens are valid for **30 days** by default;\nuse `grant_type=refresh_token` to renew without re-authenticating. Not scoped\n— prefer OAuth 2.0 for installable integrations.\n\n### Method 3 — IdClient + ApiKey\n\nTwo credentials:\n\n| Parameter  | Type    | Description |\n|------------|---------|-------------|\n| `IdClient` | integer | Your numeric Mailpro client ID, found in **Settings → API access** |\n| `ApiKey`   | string  | Your API key, found in **Settings → API access** |\n\nSend them in either of these places — pick one:\n\n1. **HTTP headers (recommended)** — `IdClient: 12345` and `ApiKey: a1b2c3d4-…`.\n   URLs are logged by web servers, CDNs and proxies, so a key in the query string\n   can leak into access logs. Headers are not logged.\n2. **Query string (legacy, still works)** — `?IdClient=12345&ApiKey=…`.\n   Kept for backward compatibility with existing integrations. Switch to\n   headers as soon as you can.\n3. **Form body (POST only)** — `IdClient=12345&ApiKey=…` in\n   `application/x-www-form-urlencoded`.\n\nIf you provide credentials in more than one place, the **header wins**.\n\n### OAuth scope enforcement per endpoint (Email v2)\n\nFor OAuth-issued tokens, each endpoint group requires a scope (legacy auth is\nexempt). Each operation lists its scope under **Authorization**. Summary:\n\n| Endpoints | Required scope |\n|-----------|----------------|\n| `/send/*` (campaigns, transactional, scheduling, test — except `/send/{IdSend}/status`) | `email:send` |\n| `/stats/*` (except `/stats/del`), `/history/list`, `/send/{IdSend}/status` | `email:read` |\n| `/message/*`, `/senderEmail/*` (read) | `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\nScope rejection returns **403** with\n`{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }`.\n\n## Response format\n\nAll endpoints support `json` (default) and `xml`. Specify the format in the URL:\n- `/email/list.json`\n- `/email/list.xml`\n\n## Pagination\n\n**Same rule on the three Mailpro APIs** (Email v2, CRM v3, SMS): **5,000 items per page,\nby default and at most.**\n- `numberOfRecords` — items per page. Omitted, `0`, or above 5,000 = 5,000.\n- `pageNumber` — 1-based page number (default 1).\n- Both are accepted as query parameters **or** HTTP headers.\n- A full page means there may be more: request the next `pageNumber` until a page\n  comes back with fewer items.\n- Pages are stable: the same call returns the same items in the same order, as long as\n  the data does not change in between.\n- Exception: message and history lists with their HTML body (`bodyHTML=true`) return\n  10 per page.\n- `/email/list` adds `X-Total-Count` (the real total) and `X-Truncated: true` when\n  contacts remain beyond the page.\n\n**Unknown parameters** are ignored, never rejected. When a request carries a parameter\nthe API does not recognise, the response includes `X-Ignored-Parameters` (the names) and\n`X-Documentation` (a link to this page), so a typo does not go unnoticed.\n\n## Error responses\n\n| HTTP | Meaning |\n|------|---------|\n| 400  | Bad request — missing or invalid required parameter |\n| 401  | Unauthorized — invalid `IdClient` or `ApiKey` |\n| 403  | Forbidden — account limit reached (e.g. max lists) |\n| 404  | Not found — the requested resource does not exist |\n| 500  | Internal server error |\n\nErrors from business rules:\n- `\"Not enough credit available.\"` → 403 — your account has no remaining email credits\n- `\"Email address unsubscribed.\"` → 400 — the recipient has unsubscribed\n\n## Delivery tracking (transactional emails)\n\nEvery **single** email you send (`POST /send/sendmail`, the CRM API v3, the SMTP relay or an automation) gets an identifier. It can be followed until the recipient's server accepts or rejects it. Campaigns are not covered here: use the statistics instead.\n\n1. **Send**: the response of `POST /send/sendmail.{format}` contains the identifier of the send.\n2. **Get the result** (recommended): the `email.delivered` and `email.bounced` webhook events push the final status to your server as soon as it is known, with no polling at all.\n3. **Or poll**: `GET /send/{IdSend}/status.{format}` returns the current status (table below).\n\n| `status` | Meaning | Final? |\n|---|---|---|\n| `queued` | Accepted, waiting to be sent. | no |\n| `scheduled` | Planned for later (`DatePlanned`). | no |\n| `sent` | Handed over by our servers, no answer from the recipient server yet. | no |\n| `delivered` | Accepted by the recipient server (`DiagCode` = its SMTP reply). | **yes** |\n| `bounced` | Rejected. `BounceType`: `hard` = invalid address or permanent refusal; `soft` = refused after retries (mailbox full, server unreachable…). | **yes** |\n| `not_found` | Unknown id, or an id that does not belong to your account. | **yes** |\n\n**Polling without looping**\n\n- Stop polling as soon as the status is **final**: it will not change any more.\n- First poll **5 minutes** after sending at the earliest: `delivered` appears about 5 minutes after the handover.\n- Then **one poll every 15 minutes at most**.\n- If you poll a non-final send before 15 minutes, you get the same answer with the `Retry-After` header (the number of seconds to wait), and the call does not count against your quota.\n- **At most 48 hours** after sending, every email has a final status: do not poll beyond that.\n- `scheduled`: no need to poll before `DatePlanned`.\n- **Every poll counts against your API request quota.** Following these rules, one send costs at most 192 requests (4 per hour for 48 hours), and far fewer in practice, since you stop at the final status. The same tracking by webhook costs a single event.\n\nStatuses are kept for **365 days**.\n\n## Webhooks\n\nMailpro™ can notify your server in real time when certain events occur on your\naccount (an email is delivered, a campaign finishes, a contact bounces, etc.).\nStripe-style — your URL receives an HMAC-SHA256 signed POST as soon as the\nevent fires.\n\nEach event sent to your webhook counts as 1 request against your API request quota.\n\n### How it works\n\n1. **Subscribe** to one or more event types via `POST /webhooks`. The response\n   contains a `secret` shown **once** (Stripe / GitHub style) — store it.\n2. **Mailpro POSTs** a signed JSON payload to your URL as soon as an event matches.\n3. **Verify the signature** server-side with your `secret` (snippets below).\n4. **Respond 200–299** within 10 seconds. Otherwise we retry with exponential\n   backoff (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, then give up).\n\n> **⏱ Activation delay** — after you create, update or delete a webhook, the\n> change takes up to **10 minutes** to propagate across the Mailpro API\n> servers. During that window events may not yet match your new subscription\n> (or may still match a just-removed one). This is the time required to\n> refresh the in-memory subscription cache on every API instance.\n\n### Payload envelope\n\nAll events share a common envelope:\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| Field | Format | Description |\n|-------|--------|-------------|\n| `id` | `evt_` + 32 hex | Unique event ID — use as an idempotency key on your side. |\n| `type` | `<domain>.<verb>` | Canonical event type. |\n| `created` | Unix seconds UTC | Included in the HMAC signature. |\n| `apiVersion` | `\"v2\"` | Which Mailpro API published the event. |\n| `account.id` | int | Your Mailpro client ID (= `IdClient`). |\n| `account.name` | string | Your account name (handy for client-side debug). |\n| `data` | object | Event payload — shape depends on `type` (see catalog below). |\n\n### Event catalog\n\n| Event | Trigger | `data` shape |\n|-------|---------|--------------|\n| `ping` | Test via `POST /webhooks/{id}/test` | `{ message }` |\n| `email.processed` | Send accepted by pipeline | `{ messageId, email, campaignId, processedAt }` |\n| `email.delivered` | A **single** email was accepted by the recipient server — API v2/v3, SMTP or Automation (**not** campaigns). Emitted from the PowerMTA delivery feed. | `{ messageId, email, idSending, sendingType, diagCode, deliveredAt }` |\n| `email.opened` | Tracking pixel hit | `{ messageId, email, campaignId, openedAt, ip, userAgent }` |\n| `email.clicked` | Click on tracked link | `{ messageId, email, campaignId, clickedAt, url, ip, userAgent }` |\n| `email.bounced` | Hard or soft bounce | `{ messageId, email, campaignId, bouncedAt, bounceType, reason }` |\n| `email.spam_report` | FBL complaint | `{ messageId, email, campaignId, reportedAt }` |\n| `email.unsubscribed` | Opt-out link clicked | `{ messageId, email, campaignId, unsubscribedAt }` |\n| `email.dropped` | Refused before send | `{ messageId, email, campaignId, droppedAt, reason }` |\n| `campaign.started` | Dispatch begins | `{ campaignId, name, totalRecipients, startedAt }` |\n| `campaign.finished` | All recipients processed | `{ campaignId, name, totalSent, totalFailed, finishedAt }` |\n| `credits.low` | Email credit balance under your alert threshold | `{ remaining, threshold }` |\n\nSubscribe to all events of this API by passing `[\"*\"]` in the `events` array.\n\n### HMAC signature\n\nEvery POST carries an `X-Mailpro-Signature` header:\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\nTo verify:\n1. Extract `t` and `v1` from the header.\n2. **Reject** if `|now - t| > 300` (5-minute replay protection window).\n3. Compute `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Constant-time compare** `v1` with `expected` (`crypto.timingSafeEqual`,\n   `hash_equals`, `CryptographicOperations.FixedTimeEquals`) — never `==`.\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### Retry and auto-disable\n\n| Attempt | Delay before next try |\n|---------|----------------------|\n| 1 → 2 | 10 seconds |\n| 2 → 3 | 1 minute |\n| 3 → 4 | 5 minutes |\n| 4 → 5 | 30 minutes |\n| 5 → 6 | 2 hours |\n| 6 → 7 | 6 hours |\n| 7 | abandoned (delivery marked `failed`) |\n\nAfter **10 consecutive failures** on the same webhook, it is **automatically\ndisabled** (`isActive: false`) and you receive a notification email. Re-enable\nit with `PUT /webhooks/{id}` once your endpoint is fixed.\n\n### Success = HTTP 2xx\n\nWe treat your webhook as successful only if you return a status in `200–299`.\nAny 3xx/4xx/5xx or a timeout (> 10 s) counts as a failure and triggers retries.\nIf your endpoint is permanently dead, return `410 Gone` explicitly — retries\nstill happen but the failure reason is clearer in your delivery log.\n\n### Limits\n\n| Limit | Value |\n|-------|-------|\n| Webhooks per account | 20 |\n| Subscribed events per webhook | 50 |\n| Max payload size | 256 KB |\n| HTTP timeout per attempt | 10 seconds |\n| Delivery history retention | 30 days |\n"
  },
  "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": "Bearer JWT token obtained from `POST /v2/token` (form-encoded, password\ngrant). The same token is also valid on the CRM API v3 and the SMS\nAPI — authenticate once, call any API.\nPass it as: `Authorization: Bearer <token>`\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Mailpro OAuth 2.0 — the modern way for third-party apps and integration\nplatforms (Zapier, Make, n8n) to act on a Mailpro user's behalf with\nscoped, revocable access tokens.\n\n- **authorizationCode + PKCE** (S256, mandatory for public clients) — the\n  \"Connect Mailpro\" consent flow. Issues an access token + a rotating\n  refresh token.\n- **clientCredentials** — machine-to-machine, no user involved.\n\nOne authorization server for all APIs, at the version-neutral surface\n`https://api.mailpro.com/oauth/` (issuer / `iss` claim\n`https://api.mailpro.com/oauth/`). Access tokens are RS256 JWTs\n(verify against the JWKS at `https://api.mailpro.com/oauth/.well-known/jwks`);\nTTL **20 minutes**. Refresh tokens are valid **30 days** (sliding) and\n**single-use** (rotated on every refresh). Authorization codes live\n**60 seconds**.\n\nThe same OAuth access token is accepted by all three Mailpro APIs\n(CRM v3, Email v2, SMS) — authenticate once, call any API; access is\ngoverned by the token's scopes, not the API base URL. Legacy auth\n(Bearer JWT / IdClient+ApiKey) keeps working unchanged and is NOT\nscope-gated.\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": "Your numeric Mailpro client ID — **preferred** transport (HTTP header).\nURLs are logged by web servers, Cloudflare and proxies, so query-string\ncredentials can leak into access logs. Headers are not logged.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "ApiKey",
        "description": "Your API key (GUID) — **preferred** transport (HTTP header).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "IdClient",
        "description": "Your numeric Mailpro client ID — **legacy**, kept for backward compatibility.\nSwitch to the `IdClient` header when you can.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "ApiKey",
        "description": "Your API key (GUID) — **legacy**, kept for backward compatibility.\n"
      }
    },
    "parameters": {
      "format": {
        "name": "format",
        "in": "path",
        "required": true,
        "description": "Response format",
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "xml"
          ],
          "default": "json"
        },
        "example": "json"
      },
      "numberOfRecords": {
        "name": "numberOfRecords",
        "in": "query",
        "description": "Items per page — 5,000 by default and at most (see Pagination).",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 50
      },
      "pageNumber": {
        "name": "pageNumber",
        "in": "query",
        "description": "Page number (1-based). Default is 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "JWT access token — use as `Authorization: Bearer <token>` in subsequent requests."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Token lifetime in seconds",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "Client ID of the authenticated user",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Token to obtain a new access token without re-authenticating"
          },
          "application": {
            "type": "string",
            "description": "Integration name (for third-party grants only)",
            "nullable": true
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "ListID": {
            "type": "integer",
            "description": "Unique identifier for the list",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Legacy alias** — same value as `ListID`. Returned for backward compatibility with older clients.",
            "example": 101
          },
          "Title": {
            "type": "string",
            "description": "Display name of the list",
            "example": "Newsletter — France"
          },
          "Type": {
            "type": "integer",
            "description": "`0` = standard contact list, `1` = blacklist (for unsubscribe management)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "NumberEmails": {
            "type": "integer",
            "description": "Total number of contacts in this list",
            "example": 4521
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "description": "Date and time the list was created",
            "example": "2025-01-15T10:30:00"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "IDMessage": {
            "type": "integer",
            "description": "Unique identifier for the message template",
            "example": 501
          },
          "Subject": {
            "type": "string",
            "description": "Email subject line",
            "example": "Spring Newsletter — April 2026"
          },
          "Language": {
            "type": "string",
            "description": "Language code used for the unsubscribe link localization",
            "example": "EN"
          },
          "LinkAlign": {
            "type": "string",
            "description": "Horizontal alignment of the unsubscribe link",
            "enum": [
              "left",
              "center",
              "right"
            ],
            "example": "center"
          },
          "LinkUp": {
            "type": "integer",
            "description": "Position of the unsubscribe link — `0` = bottom, `1` = top",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "BodyHTML": {
            "type": "string",
            "description": "Full HTML content of the email (returned only when `bodyHTML=true`)",
            "example": "<h1>Welcome!</h1><p>This is our spring newsletter.</p>"
          },
          "UpdateDate": {
            "type": "string",
            "format": "date-time",
            "description": "Date and time the template was last modified",
            "example": "2026-03-10T14:22:00"
          }
        }
      },
      "SenderEmail": {
        "type": "object",
        "properties": {
          "IDEmailExp": {
            "type": "integer",
            "description": "Unique identifier for the sender email address",
            "example": 201
          },
          "Email": {
            "type": "string",
            "description": "Sender email address (must be verified before use)",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Display name shown as the sender in recipients' email clients",
            "example": "Your Company Newsletter"
          },
          "IsValid": {
            "type": "boolean",
            "description": "`true` if the email address has been verified by Mailpro",
            "example": true
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "example": "2025-06-01T09:00:00"
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "IDSend": {
            "type": "integer",
            "description": "Unique identifier for this send / campaign",
            "example": 3001
          },
          "ListID": {
            "type": "integer",
            "description": "ID of the recipient list used",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Legacy alias** — same value as `ListID`.",
            "example": 101
          },
          "IDCampaign": {
            "type": "integer",
            "description": "ID of the campaign statistics record (if Campaign=1 was set at send time)",
            "example": 8001
          },
          "SenderEmail": {
            "type": "string",
            "description": "Email address of the sender",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Display name of the sender",
            "example": "Your Company Newsletter"
          },
          "DatePlanned": {
            "type": "string",
            "format": "date-time",
            "description": "Scheduled send date and time",
            "example": "2026-04-20T09:00:00"
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Subject line of the email",
            "example": "Spring Newsletter — April 2026"
          },
          "NumberCredit": {
            "type": "integer",
            "description": "Number of email credits consumed by this send",
            "example": 4521
          }
        }
      },
      "HistoryEntry": {
        "type": "object",
        "properties": {
          "IDHistoric": {
            "type": "integer",
            "description": "Unique identifier for this history entry",
            "example": 9001
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Subject line of the sent email",
            "example": "Spring Newsletter — April 2026"
          },
          "DateSend": {
            "type": "string",
            "format": "date-time",
            "description": "Date and time the email was sent",
            "example": "2026-04-20T09:00:01"
          },
          "NumberSend": {
            "type": "integer",
            "description": "Total number of emails sent in this campaign",
            "example": 4521
          },
          "NumberOpen": {
            "type": "integer",
            "description": "Number of unique opens recorded",
            "example": 1823
          },
          "NumberClick": {
            "type": "integer",
            "description": "Number of unique link clicks recorded",
            "example": 342
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Webhook ID (Mailpro)",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS endpoint that receives events",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Subscribed event types",
            "example": [
              "email.delivered",
              "email.bounced",
              "campaign.finished"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Slack integration"
          },
          "is_active": {
            "type": "boolean",
            "description": "When `false`, no event is delivered. Auto-disabled after 10 consecutive failures.",
            "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": "When the most recent delivery was attempted",
            "example": "2026-07-21T18:56:07.653"
          },
          "last_delivery_status": {
            "type": "integer",
            "nullable": true,
            "description": "HTTP status returned by your endpoint on the most recent delivery",
            "example": 200
          },
          "consecutive_failures": {
            "type": "integer",
            "description": "Reset to 0 on the first success; at 10 the webhook is auto-disabled",
            "example": 0
          }
        }
      },
      "WebhookList": {
        "type": "object",
        "description": "Envelope returned by `GET /webhooks`.",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "total": {
            "type": "integer",
            "description": "Total number of webhooks on the account",
            "example": 2
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS endpoint (HTTP refused in production)",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "List of event types to subscribe to (see catalog above). Use `[\"*\"]` to subscribe to all events of this 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": "HMAC secret. **Shown once here, never again.** Store it server-side.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Partial update — every field is optional.",
        "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": "Set `true` to re-enable an auto-disabled webhook once your endpoint is fixed."
          }
        }
      },
      "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": "Obtain a Bearer JWT token to authenticate all other API calls. The\nv2 `/token` endpoint is a 307 redirect to the canonical `/v3/token`\nissuer — your HTTP client follows the redirect transparently (POST\nmethod and body are preserved).\n"
    },
    {
      "name": "Account",
      "description": "Check your email credit balance, monthly API quota, and subscription status."
    },
    {
      "name": "Lists",
      "description": "Manage lists (contact lists). A list groups contacts for bulk campaigns.\n**Maximum 1,000 lists per account** (same limit on the three Mailpro APIs and in the app).\n`Type 0` = standard list. `Type 1` = blacklist (used for unsubscribe management).\n"
    },
    {
      "name": "Contacts",
      "description": "Manage individual email contacts. Contacts belong to one or more lists.\nUse bulk import (`/email/add`) for large batches, or single-contact add (`/email/addSingle`)\nfor individual sign-ups with custom field values.\n"
    },
    {
      "name": "Messages",
      "description": "Manage HTML email templates. A message template stores your email subject,\nHTML body, and unsubscribe link configuration.\nTemplates are reused across campaigns.\n"
    },
    {
      "name": "Campaigns",
      "description": "Send bulk email campaigns to a list and manage scheduled sends.\nA campaign uses a message template and a sender address.\n"
    },
    {
      "name": "Transactional",
      "description": "Send one-off transactional emails to individual recipients.\nUnlike campaigns, transactional emails do not require a list —\nyou pass the recipient email and HTML body directly.\n"
    },
    {
      "name": "Sender Addresses",
      "description": "List and manage validated sender email addresses.\nOnly verified addresses can be used as the `From` address in campaigns.\n"
    },
    {
      "name": "Statistics",
      "description": "Access per-campaign performance metrics: opens, clicks, bounces, and more.\nDetailed breakdowns by hour, day, country, OS, and email client are available.\n"
    },
    {
      "name": "History",
      "description": "Browse the complete log of all past email sends.\n"
    },
    {
      "name": "Import",
      "description": "Upload a CSV or XLSX file to import email contacts into a list in bulk.\nThe file is queued for asynchronous processing — track completion via\nthe `ImportJobId` returned or via the optional `WebhookUrl` callback.\n"
    },
    {
      "name": "Webhooks",
      "description": "Subscribe your server to real-time event notifications. Mailpro POSTs an\nHMAC-signed JSON payload to your URL as soon as the subscribed event happens.\nSee the \"Webhooks\" section in the introduction for the full event catalog,\npayload envelope, signature verification snippets, and retry policy.\n"
    },
    {
      "name": "Suppression",
      "description": "Bounces and unsubscribers of the account: list, add, remove."
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getEmailAccessToken",
        "summary": "Get access token (307 redirect to /v3/token)",
        "security": [],
        "description": "Obtains a Bearer JWT token using Mailpro client credentials.\nPass the returned `access_token` as `Authorization: Bearer <token>` in all\nsubsequent requests. The same token is also valid on the CRM API v3 and\nthe SMS API.\n\n> **⚙ Implementation detail** — `POST /v2/token` is a **307 Temporary\n> Redirect** to `POST /v3/token` (configured at the IIS `web.config`\n> rewrite layer). HTTP 307 preserves both the **method** (`POST`) and\n> the **request body**, so any standards-compliant HTTP client follows\n> the redirect transparently — you keep posting to `/v2/token` and get\n> a valid JWT back. There is no duplicated token-issuance logic; the\n> Email v2 API never issues tokens itself.\n\n### Supported grant types\n| Grant type | Use case |\n|------------|----------|\n| `password` | Standard integration — username + API key |\n| `refresh_token` | Renew an expiring access token without re-authenticating |\n| `client_credentials` | Server-to-server with client ID only |\n\n### Token lifetime\n- Access token: **30 days**\n- Refresh token: **90 days**\n\nUse `grant_type=refresh_token` to renew the access token without\nre-authenticating. Store tokens server-side (Vault, env vars); never\nembed in browser JS or mobile app binaries. See the CRM API v3\n`/token` doc for the full security note.\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": "Your Mailpro username (email). Required for `password` grant.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "Your Mailpro API key (GUID format). Required for `password` grant.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Previous refresh token. Required for `refresh_token` grant."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Your Mailpro client ID (integer). Required for `client_credentials` grant.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued successfully. Returned by `POST /v3/token` after the\ntransparent 307 follow — your HTTP client sees a normal 200 with\nthe same body shape it would receive directly from the v3 token\nendpoint.\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": "Temporary Redirect to `POST /v3/token`, issued by the IIS rewrite\nrule in `web.config`. Standards-compliant HTTP clients follow this\nautomatically and preserve the original POST method + form body.\nVisible only to clients that explicitly disable redirect following\n(e.g. `curl --max-redirs 0`).\n",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "example": "https://api.mailpro.com/v3/token"
              }
            }
          },
          "400": {
            "description": "Invalid credentials or unsupported grant type",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Wrong credentials",
                    "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": "Get email credit balance",
        "description": "Returns the remaining email credit balance for your Mailpro account.\nEach email sent consumes one credit. Credits do not expire with the subscription,\nbut are only usable while the subscription is active.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Credit balance returned successfully",
            "content": {
              "application/json": {
                "example": {
                  "Credits": 48500
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/account/subscriptionEndDate.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSubscriptionEndDate",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Get subscription end date",
        "description": "Returns the expiry date of the current Mailpro subscription.\nAfter the expiry date, sends are blocked until the subscription is renewed.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription end date returned successfully",
            "content": {
              "application/json": {
                "example": {
                  "SubscriptionEndDate": "2027-01-15T00:00:00"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Get monthly API quota",
        "description": "Returns the monthly API request quota for the authenticated client.\n\n**Quota calculation:** the limit is calibrated from the email\nsubscription credits (typically `subscription_credits × 5`). For\na 10,000-email/month plan, this yields a 50,000-request monthly\nbudget. Reset on the **subscription anniversary date** (not the\n1st of the calendar month).\n\n**What consumes credits:**\n- Every authenticated API request to `v2`, `v3` or `sms` endpoints.\n- Every webhook event dispatched to a subscribed endpoint.\n\n**What is FREE (does not consume credits):**\n- `/health` endpoints.\n- Requests that fail with `401`, `403` or `429`.\n- Webhook events for clients with no matching subscription.\n\nThe quota is **shared across all 3 Mailpro APIs** (`v2`, `v3`, `sms`)\n— one client = one monthly budget across the whole platform.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Quota snapshot",
            "content": {
              "application/json": {
                "example": {
                  "MonthlyLimit": 50000,
                  "Remaining": 32847,
                  "Used": 17153,
                  "IsFree": false,
                  "RemainedSendsForFree": 0
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "No quota record found (newly created account; row will be created on the first authenticated request)."
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listLists",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List all lists",
        "description": "Returns all lists for the account, ordered by creation date (newest first)\nunless `sortByName=true` is set.\nUse `type=0` for regular lists or `type=1` for blacklists.\n\n> **Legacy alias:** `/addressbook/list.{format}` — same endpoint, kept for backward\n> compatibility. New integrations should use `/list/*`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleFilter",
            "in": "query",
            "description": "Filter by title (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`0` = standard lists only, `1` = blacklists only. Omit to return all.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Set to `true` to sort results alphabetically by title",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lists returned successfully.\n\n> The response also contains a legacy duplicate field `AddressBookList` (identical content)\n> and each item has a legacy duplicate `AddressBookID` (identical to `ListID`). New\n> integrations should ignore them.\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": "Invalid credentials"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Create a list",
        "description": "Creates a new list (contact list).\nThe list starts empty — add contacts with `/email/add` or `/email/addSingle`.\n**Maximum 1,000 lists per account** (same limit on the three Mailpro APIs and in the app). Returns HTTP 422 if the limit is reached.\n\n> **Legacy alias:** `/addressbook/add.{format}` — same endpoint, kept for backward compatibility.\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": "Display name for the new list",
                    "example": "Spring Campaign 2026"
                  },
                  "Type": {
                    "type": "integer",
                    "description": "`0` = standard list (default), `1` = blacklist",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List created successfully.\n\n> A legacy duplicate field `AddressBookList` is also returned (identical content).\n",
            "content": {
              "application/json": {
                "example": {
                  "Lists": [
                    {
                      "ListID": 103,
                      "Title": "Spring Campaign 2026",
                      "Type": 0,
                      "NumberEmails": 0,
                      "CreationDate": "2026-04-14T12:00:00"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing Title"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "422": {
            "description": "List limit (1,000) reached"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rename a list",
        "description": "Updates the title of an existing list.\nThe contacts inside are not affected.\n\n> **Legacy alias:** `/addressbook/edit.{format}` — same endpoint, kept for backward compatibility.\n> The `AddressBookID` parameter name is also accepted as a legacy alias for `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": "ID of the list to rename (from `/list/list`). Legacy alias `AddressBookID` is also accepted.",
                    "example": 101
                  },
                  "Title": {
                    "type": "string",
                    "description": "New title for the list",
                    "example": "Newsletter — Europe"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List renamed successfully"
          },
          "400": {
            "description": "Missing ListID or Title"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "List not found"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Delete a list",
        "description": "Permanently deletes a list **and all the contacts it contains**.\nThis action cannot be undone.\n\n> **Legacy alias:** `/addressbook/del.{format}` — same endpoint, kept for backward compatibility.\n> The `AddressBookID` parameter name is also accepted as a legacy alias for `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": "ID of the list to delete. Legacy alias `AddressBookID` is also accepted.",
                    "example": 101
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List deleted successfully",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "Missing ListID"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "List not found"
          }
        }
      }
    },
    "/email/list.{format}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "listEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List contacts",
        "description": "Returns a paginated list of email contacts for the account.\nFilter by list or by email pattern.\nResults are ordered alphabetically when `sortByName=true`, otherwise by insertion order.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filter by email address (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "name": "listId",
            "in": "query",
            "description": "Return only contacts in this list. Legacy alias `addressBookId` is also accepted.",
            "schema": {
              "type": "integer"
            },
            "example": 101
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Set to `true` to sort results alphabetically by email address",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contact list returned successfully",
            "content": {
              "application/json": {
                "example": {
                  "Emails": [
                    {
                      "IdEmail": 10001,
                      "Email": "alice@example.com",
                      "Field1": "Alice",
                      "Field2": "Dupont"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/email/add.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Import contacts (bulk)",
        "description": "Imports one or more email addresses into a list in a single request.\nProvide addresses in `EmailList` separated by semicolons.\n\n**Example:** `alice@example.com;bob@example.com;carol@example.com`\n\nThis endpoint only imports email addresses. To also set custom field values,\nuse `/email/addSingle` for each contact instead.\n\nPreviously unsubscribed addresses are silently skipped unless `Force=1` is set.\n\n**List selection:** provide `ListId` (or its legacy alias `AddressBookId`). At least one is required.\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": "ID of the destination list. Legacy alias `AddressBookId` is also accepted.",
                    "example": 101
                  },
                  "EmailList": {
                    "type": "string",
                    "description": "Semicolon-separated email addresses to import",
                    "example": "alice@example.com;bob@example.com;carol@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Set to `1` to re-import addresses that were previously unsubscribed.\nDefault: `0` (unsubscribed addresses are skipped).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacts imported successfully",
            "content": {
              "application/json": {
                "example": {
                  "Result": "3 contacts imported"
                }
              }
            }
          },
          "400": {
            "description": "Missing EmailList"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/email/addSingle.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addSingleEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Add a single contact",
        "description": "Adds one contact to a list with optional custom field values.\n\n`Field1` through `Field25` map to the custom column definitions of your list.\nThe mapping depends on the order columns were defined — check your list settings\nin the Mailpro interface to see which field number corresponds to which column\n(e.g. Field1 = FirstName, Field2 = LastName, Field3 = City…).\n\n**List selection:** provide `ListId` (or its legacy alias `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": "ID of the destination list. Legacy alias `AddressBookId` is also accepted.",
                    "example": 101
                  },
                  "Email": {
                    "type": "string",
                    "description": "Email address of the new contact",
                    "example": "alice@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Set to `1` to re-add a previously unsubscribed address",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Value for custom field 1 (column mapping depends on your list)",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Value for custom field 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Value for custom field 3",
                    "example": "Paris"
                  },
                  "Field4": {
                    "type": "string",
                    "description": "Value for custom field 4"
                  },
                  "Field5": {
                    "type": "string",
                    "description": "Value for custom field 5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact added successfully",
            "content": {
              "application/json": {
                "example": {
                  "EmailId": 10002,
                  "Email": "alice@example.com",
                  "Field1": "Alice",
                  "Field2": "Dupont",
                  "ListID": 101
                }
              }
            }
          },
          "400": {
            "description": "Missing Email"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/email/edit.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "editEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Update a contact",
        "description": "Updates the email address and/or custom field values of an existing contact.\nIdentify the contact by `EmailId` (from `/email/list`).\nBoth `EmailId` and `Email` are required.\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": "ID of the contact to update (from `/email/list`)",
                    "example": 10001
                  },
                  "Email": {
                    "type": "string",
                    "description": "New email address for the contact",
                    "example": "alice.updated@example.com"
                  },
                  "Field1": {
                    "type": "string",
                    "description": "New value for custom field 1",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "New value for custom field 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "New value for custom field 3"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact updated successfully"
          },
          "400": {
            "description": "Missing EmailId or Email"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Contact not found"
          }
        }
      }
    },
    "/email/del.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "deleteEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Delete a contact",
        "description": "Permanently deletes a contact by its unique identifier.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailId"
                ],
                "properties": {
                  "EmailId": {
                    "type": "integer",
                    "description": "ID of the contact to delete (from `/email/list`)",
                    "example": 10001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact deleted successfully"
          },
          "400": {
            "description": "Missing EmailId"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Contact not found"
          }
        }
      }
    },
    "/message/list.{format}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List message templates",
        "description": "Returns saved HTML email templates for the account.\nBy default, the HTML body is **not** included in the response to keep payloads small.\nSet `bodyHTML=true` to include it (automatically limits results to 10 per page).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectFilter",
            "in": "query",
            "description": "Filter by subject (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Set to `true` to include the full HTML body in each result.\nWhen `true`, results are automatically limited to 10 per page regardless of `numberOfRecords`.\n",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Message templates returned successfully",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/message/add.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "addMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Create a message template",
        "description": "Creates a new HTML email template.\nThe template stores the subject, HTML body, and unsubscribe link settings.\nOnce created, use the returned `IDMessage` when launching a campaign.\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": "Email subject line (max 255 characters)",
                    "example": "Spring Newsletter — April 2026"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Full HTML content of the email body",
                    "example": "<h1>Spring is here!</h1><p>Check out our latest offers.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Language code for unsubscribe link localization (e.g. `EN`, `FR`, `DE`)",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "description": "Horizontal alignment of the unsubscribe link",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "description": "Position of the unsubscribe link — `0` = bottom of email, `1` = top",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message template created successfully",
            "content": {
              "application/json": {
                "example": {
                  "IDMessage": 502,
                  "Subject": "Spring Newsletter — April 2026",
                  "Language": "EN",
                  "LinkAlign": "center",
                  "LinkUp": 0
                }
              }
            }
          },
          "400": {
            "description": "Missing required field"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/message/edit.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "editMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Update a message template",
        "description": "Updates the content and metadata of an existing message template.",
        "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": "ID of the message template to update (from `/message/list`)",
                    "example": 501
                  },
                  "Subject": {
                    "type": "string",
                    "description": "New email subject line",
                    "example": "Spring Newsletter — April 2026 (revised)"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "New HTML content of the email body",
                    "example": "<h1>Spring is here!</h1><p>Updated content.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Language code for unsubscribe link localization",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message template updated successfully"
          },
          "400": {
            "description": "Missing required field"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Message template not found"
          }
        }
      }
    },
    "/message/del.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "deleteMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Delete a message template",
        "description": "Permanently deletes a message template by its unique identifier.\nTemplates used by pending scheduled campaigns cannot be deleted.\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": "ID of the message template to delete (from `/message/list`)",
                    "example": 501
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message template deleted successfully"
          },
          "400": {
            "description": "Missing MessageId"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Message template not found"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List scheduled campaigns",
        "description": "Returns the list of scheduled and recently processed email campaigns.\nResults are ordered by planned send date (most recent first).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filter by campaign subject (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign list returned successfully",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/send/campaign.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Launch a campaign",
        "description": "Schedules or immediately sends an email campaign to a list\nusing a saved message template and a sender address.\n\n**Required:**\n- `IDMessage` — the template to send (from `/message/list`)\n- `IDEmailExp` — the sender address to use (from `/senderEmail/list`)\n- `ListId` — the recipient list (from `/list/list`). Legacy alias `IDAddressBook` is also accepted.\n\n**Scheduling:** set `DatePlanned` to a future ISO 8601 date/time to schedule the send.\nOmit `DatePlanned` to send immediately.\n\n**Statistics tracking:** set `Campaign=1` and provide a `TitleCampaign` to enable\nopen/click/bounce tracking in the Statistics section.\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": "ID of the recipient list (from `/list/list`). Legacy alias `IDAddressBook` is also accepted.",
                    "example": 101
                  },
                  "IDMessage": {
                    "type": "integer",
                    "description": "ID of the message template to send (from `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID of the sender email address to use (from `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDUnsubscribeList": {
                    "type": "integer",
                    "description": "List used to collect unsubscribed contacts (blacklist).\nLegacy alias `IDUnsubscribeAddressBook` is also accepted.\n",
                    "example": 102
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Scheduled send date/time (ISO 8601). Omit to send immediately.",
                    "example": "2026-04-20T09:00:00"
                  },
                  "Campaign": {
                    "type": "integer",
                    "description": "Set to `1` to track this send as a named campaign in statistics",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 1
                  },
                  "TitleCampaign": {
                    "type": "string",
                    "description": "Campaign title shown in statistics (required when `Campaign=1`)",
                    "example": "Spring Newsletter April 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign scheduled or sent successfully.\n\n> The response also returns legacy aliases `AddressBookID` and `UnsubscribeAddressBookID`\n> (identical to `ListID` / `UnsubscribeListID`). New integrations should ignore them.\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": "Missing IDMessage or IDEmailExp"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "403": {
            "description": "Not enough email credits"
          },
          "404": {
            "description": "List, message, or sender not found"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "deleteCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancel or delete a campaign",
        "description": "Cancels a **pending scheduled** campaign send, or deletes a **completed** one.\nOnly future-scheduled sends can be cancelled — sends in progress cannot be stopped.\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": "ID of the campaign send to cancel or delete (from `/send/list`)",
                    "example": 3001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign cancelled or deleted successfully",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Campaign Deleted"
                }
              }
            }
          },
          "400": {
            "description": "Missing IdSend"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Campaign not found"
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listScheduledCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List my scheduled email campaigns",
        "description": "Returns the email campaigns and single sends scheduled for a future date that\nhave not yet been dispatched. Useful before calling `/cancel` or `/reschedule`.\nRecords are sorted by `DatePlanned` ascending.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "List of scheduled campaigns / sends.\n\n> Each record also includes legacy aliases `AddressBookID` and\n> `UnsubscribeAddressBookID` (identical to `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": "Invalid credentials"
          }
        }
      }
    },
    "/send/{IdSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "cancelScheduledCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancel a scheduled campaign / send",
        "description": "Cancels a scheduled email send (campaign or single) that has not yet been dispatched.\nIf the send has already gone out (or doesn't exist / belongs to another client),\nreturns **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Send cancelled",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 5001
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          },
          "409": {
            "description": "Already dispatched or not found"
          }
        }
      }
    },
    "/send/{IdSend}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "rescheduleCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reschedule a scheduled campaign / send",
        "description": "Updates the `DatePlanned` of a scheduled email send. New date must be\n**in the future** and **within 90 days**.\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": "Send rescheduled",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSend": 5001,
                  "NewPlanDate": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid PlanDate"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "409": {
            "description": "Already dispatched, not found, or new date out of range (must be future and within 90 days)"
          }
        }
      }
    },
    "/send/mail/scheduled.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "listScheduledMails",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List scheduled single emails",
        "description": "Returns the single emails sent with `/send/sendmail` and a future date that have not left yet. Campaigns are listed by `/send/scheduled`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Scheduled emails returned",
            "content": {
              "application/json": {
                "example": {
                  "scheduledMails": [
                    {
                      "IdSingleSend": 880123,
                      "Email": "jane@example.com",
                      "Subject": "Your invoice",
                      "DatePlanned": "2026-12-01T09:00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "cancelMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancel a scheduled single email",
        "description": "Cancels the email as long as it has not left.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` returned by `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email cancelled",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 880123
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          },
          "409": {
            "description": "Send not found, or already dispatched"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/reschedule.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "rescheduleMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reschedule a scheduled single email",
        "description": "Changes the send date. The new date must be in the future and within 90 days. `PATCH` is also accepted.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` returned by `/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": "New send date (ISO 8601)",
                    "example": "2026-12-15T09:00:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email rescheduled",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSingleSend": 880123,
                  "NewPlanDate": "2026-12-15T09:00:00"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid date"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "409": {
            "description": "Send not found, already dispatched, or date out of range"
          }
        }
      }
    },
    "/send/sendingTest.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendTestEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Send a test email",
        "description": "Sends a preview of a message template to a specified recipient for review\nbefore launching the real campaign.\nThe sender, template, and test recipient are all identified by their IDs.\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": "ID of the message template to preview (from `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExpFrom": {
                    "type": "integer",
                    "description": "ID of the sender address to use (from `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDEmailExpTo": {
                    "type": "integer",
                    "description": "ID of the recipient sender address — the test email is sent to this address",
                    "example": 202
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Test email sent successfully",
            "content": {
              "application/json": {
                "example": {
                  "SendingTest": {
                    "IdSendingTest": 7001,
                    "ToEmail": "test@yourcompany.com",
                    "FromEmail": "newsletter@yourcompany.com",
                    "SenderName": "Your Company Newsletter"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing required field"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/send/sendmail.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "sendTransactionalEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Send a transactional email",
        "description": "Sends a one-off transactional email to one or more recipients.\nUnlike campaigns, this endpoint does not require a list —\nthe recipient address and HTML body are passed directly.\n\n**Required:**\n- `IDEmailExp` — the sender address ID (from `/senderEmail/list`)\n- `EmailData` — recipient in `email,field1,field2,...,field25` format (comma-separated)\n- `BodyHTML` — the HTML body\n- `Subject` — the subject line\n\n**EmailData format:** `alice@example.com,Alice,Dupont,Paris`\nThe first value is the email address; values 2–26 map to Field1–Field25 for\npersonalization variables in your HTML template.\n\n**Multiple recipients:** separate multiple `EmailData` entries with semicolons:\n`alice@example.com,Alice;bob@example.com,Bob`\n\n**Scheduling:** set `DatePlanned` to a future ISO 8601 date/time, or omit to send immediately.\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": "ID of the sender email address to use (from `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Recipient in `email,field1,field2,...,field25` format (comma-separated).\nThe first value is the email address; remaining values are personalization\nfields mapped to Field1–Field25 in your HTML template.\n\n**Local part** of the email (before `@`) accepts letters, digits and\n`. _ - +` — including RFC 5322 sub-addressing (`user+tag@domain`,\ne.g. Gmail, Fastmail, Proton). Other special characters RFC 5322\npermits (e.g. `! # $ % & ' * / = ? ^ { | } ~`) and quoted local\nparts are **not** accepted.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Full HTML content of the email body",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Email subject line (max 255 characters)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "array",
                    "maxItems": 5,
                    "description": "Optional file attachments — send the request as `multipart/form-data` and add one\nfile part per attachment (any field name). Up to **5 files**, **10 MB per file**,\n**15 MB total**. Accepted types: PDF, Word, Excel, PowerPoint, images (JPG, PNG, GIF,\nWebP), ZIP, CSV, TXT — executable and script files are rejected. **Billing:** the send keeps its usual 1 credit, plus **1 credit per 512 KB of\nattachments beyond the first 512 KB** (attachments up to ~512 KB add nothing). Every other field of\nthis endpoint (`ReplyTo`, `ActivateStatistics`, `CustomHeaders`, …) works exactly as\nin the form-urlencoded variant.\n",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (default): the attachments are used for this send only — they are stored outside\nyour account, do not count toward your storage quota and are deleted automatically after\n35 days. `true`: the attachments are also kept in your account's files (folder\n`Secure/Files/Sending/api`) and count toward your storage quota.\n",
                    "example": false
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID of the sender email address to use (from `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Recipient in `email,field1,field2,...,field25` format (comma-separated).\nThe first value is the email address; remaining values are personalization\nfields mapped to Field1–Field25 in your HTML template.\n\n**Local part** of the email (before `@`) accepts letters, digits and\n`. _ - +` — including RFC 5322 sub-addressing (`user+tag@domain`,\ne.g. Gmail, Fastmail, Proton). Other special characters RFC 5322\npermits (e.g. `! # $ % & ' * / = ? ^ { | } ~`) and quoted local\nparts are **not** accepted.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Full HTML content of the email body",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Email subject line (max 255 characters)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "string",
                    "description": "Optional file attachments as a **JSON array** of `{ \"filename\": …, \"content\": … }`\nobjects, with `content` **Base64-encoded** (same shape as the CRM API v3). Up to\n**5 files**, **10 MB per file** and **15 MB total** (after decoding). Common document\nand image formats are accepted; executable and script files are rejected.\n**Billing:** the send keeps its usual 1 credit, plus **1 credit per 512 KB of\nattachments beyond the first 512 KB**. *Alternatively, send files as\n`multipart/form-data` parts (see the multipart request body above) — both work.*\n",
                    "example": "[{\"filename\":\"invoice.pdf\",\"content\":\"JVBERi0xLjQK...\"}]"
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (default): the attachments are used for this send only — they are stored outside\nyour account, do not count toward your storage quota and are deleted automatically after\n35 days. `true`: the attachments are also kept in your account's files (folder\n`Secure/Files/Sending/api`) and count toward your storage quota.\n",
                    "example": false
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Scheduled send date/time (ISO 8601). Omit to send immediately.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "ActivateStatistics": {
                    "type": "boolean",
                    "description": "Set to `true` to track opens and clicks for this email",
                    "default": false,
                    "example": true
                  },
                  "ReplyTo": {
                    "type": "string",
                    "description": "Reply-to email address. If omitted, replies go to the sender address.",
                    "example": "support@yourcompany.com"
                  },
                  "UnsubscriptionLink": {
                    "type": "boolean",
                    "description": "Set to `true` to append an unsubscribe link to the email body",
                    "default": false,
                    "example": false
                  },
                  "CustomHeaders": {
                    "type": "string",
                    "description": "Additional SMTP headers as a semicolon-separated `key=value` string",
                    "example": "X-Campaign-ID=campaign_42;X-Priority=1"
                  },
                  "BodyText": {
                    "type": "string",
                    "description": "Plain-text fallback for email clients that do not render HTML",
                    "example": "Hello Alice, your order has been confirmed."
                  },
                  "List_Unsubscribe": {
                    "type": "string",
                    "description": "Value for the `List-Unsubscribe` email header (URL or mailto)",
                    "example": "https://yourcompany.com/unsubscribe?token=abc123"
                  },
                  "List_Unsubscribe_Post": {
                    "type": "string",
                    "description": "Value for the `List-Unsubscribe-Post` header (RFC 8058)",
                    "example": "List-Unsubscribe=One-Click"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transactional email sent or scheduled successfully",
            "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": "Missing required field or invalid email format"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "403": {
            "description": "Not enough email credits"
          },
          "404": {
            "description": "Sender not found or email address unsubscribed"
          }
        }
      }
    },
    "/send/{IdSend}/status.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "getTransactionalStatus",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Get delivery status of a transactional email",
        "description": "Returns the current delivery status of a transactional email sent with `/send/sendmail`. Pass the `IdSingleSend` that call returned.\n\nPossible values: `delivered` (accepted by the recipient server, see `DiagCode`), `bounced` (rejected — `BounceType: hard` invalid address or permanent refusal, `soft` refused after retries), `sent` (handed to the mail server, no answer yet), `scheduled` (not sent yet, `DatePlanned` in the future) and `queued` (waiting to be dispatched). `delivered` and `bounced` are final: stop polling. Every email has a final status at most 48 hours after sending; poll every 15 minutes at most (each call counts against your API quota) or use the `email.delivered` / `email.bounced` webhooks. Only the client that sent the email can read its status — any other id returns 404.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "description": "The `IdSingleSend` returned by `/send/sendmail`.",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Current delivery status",
            "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": "Invalid credentials"
          },
          "404": {
            "description": "No transactional send found with this id for this client"
          }
        }
      }
    },
    "/senderEmail/list.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "listSenderEmails",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List validated sender addresses",
        "description": "Returns the list of sender email addresses configured for the account.\nOnly addresses with `IsValid: true` can be used when sending campaigns.\nNew addresses are added with `/senderEmail/add` and become valid once the link in the validation email is clicked.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filter by email address (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "@yourcompany.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Set to `true` to sort results by sender name alphabetically",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sender addresses returned successfully",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/senderEmail/add.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "addSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Add a sender address",
        "description": "Adds the address with the same checks as the app and sends it a validation email. It can be used once the link in that email is clicked. An account can have up to 25 senders, validated or pending.",
        "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": "Sender address",
                    "example": "news@example.com"
                  },
                  "SenderName": {
                    "type": "string",
                    "description": "Name shown to recipients",
                    "example": "Example News"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Address added. `DomainHasMx` is false when the domain has no MX record.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true,
                  "DomainHasMx": true
                }
              }
            }
          },
          "400": {
            "description": "`Email` or `SenderName` missing"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "422": {
            "description": "Address refused: invalid, already among the senders of the account, public mail domain, forbidden name, or limit of 25 reached. The message gives the reason."
          },
          "503": {
            "description": "Temporarily unavailable, please try again"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/resendValidation.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "resendSenderValidation",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Send the validation email again",
        "description": "For an address still waiting for validation.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID of the sender, from `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email sent again",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Sender not found"
          },
          "409": {
            "description": "This sender is already validated"
          },
          "503": {
            "description": "Temporarily unavailable, please try again"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/authentication.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "getSenderAuthentication",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Check the domain of a sender (SPF, DKIM, DMARC, MX)",
        "description": "Checks the domain live in DNS and returns the records to publish. Read-only. DKIM is activated in the app: `DkimSettingsUrl` opens the right screen.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID of the sender, from `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status of the domain. `Spf.RecommendedRecord` is built on your current record: publish it only when `Spf.ChangeNeeded` is 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": "Invalid credentials"
          },
          "404": {
            "description": "Sender not found"
          },
          "503": {
            "description": "Temporarily unavailable, please try again"
          }
        }
      }
    },
    "/senderEmail/del.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "deleteSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remove a sender address",
        "description": "Removes a validated sender email address from the account.\nSender addresses used by scheduled campaigns cannot be deleted.\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": "ID of the sender address to remove (from `/senderEmail/list`)",
                    "example": 201
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sender address removed successfully",
            "content": {
              "application/json": {
                "example": {
                  "Result": "EmailSender Deleted"
                }
              }
            }
          },
          "400": {
            "description": "Missing idEmailExp"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/list.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "listStats",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List campaign statistics",
        "description": "Returns per-campaign performance metrics: sent, opens, clicks, bounces\n(`BadMail`), unsubscribes, complaints, spam-trap hits and the deliverability\nscore. Filter by date range or campaign title. Results are ordered by send\ndate (most recent first).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleCampaignFilter",
            "in": "query",
            "description": "Filter by campaign title (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "spring"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "dateStart",
            "in": "query",
            "description": "Start of date range filter (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-01-01T00:00:00"
          },
          {
            "name": "dateEnd",
            "in": "query",
            "description": "End of date range filter (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-12-31T23:59:59"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign statistics returned successfully",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/stats/byHour.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByHour",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Statistics by hour",
        "description": "Returns the hourly open and click breakdown for a specific campaign.\nUseful for understanding the optimal send time.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID of the campaign (from `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Hourly statistics returned successfully",
            "content": {
              "application/json": {
                "example": {
                  "ByHour": [
                    {
                      "Hour": 9,
                      "Opens": 823,
                      "Clicks": 142
                    },
                    {
                      "Hour": 10,
                      "Opens": 512,
                      "Clicks": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/byDay.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByDay",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Statistics by day",
        "description": "Returns the daily open and click breakdown for a specific campaign.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID of the campaign (from `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Daily statistics returned successfully"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/del.{format}": {
      "post": {
        "tags": [
          "Statistics"
        ],
        "operationId": "deleteStats",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Delete campaign statistics",
        "description": "Permanently deletes all statistics records for a given campaign.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IdCampaign"
                ],
                "properties": {
                  "IdCampaign": {
                    "type": "integer",
                    "description": "ID of the campaign whose statistics to delete (from `/stats/list`)",
                    "example": 8001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign statistics deleted successfully",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Statistic Deleted"
                }
              }
            }
          },
          "400": {
            "description": "Missing IdCampaign"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Campaign not found"
          }
        }
      }
    },
    "/stats/country.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsCountry",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Geolocation breakdown",
        "description": "Returns the geolocation breakdown of campaign opens — how many opens came\nfrom each country.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Country breakdown returned"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/open.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsOpens",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Open events log",
        "description": "Returns the per-recipient log of open events for a campaign (one row per open).\nUse `emailFilter` to search for a specific recipient (partial, case-insensitive).\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": "Open events returned"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/click.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsClicks",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Click events log",
        "description": "Returns the per-recipient log of click events for a campaign — including\nwhich link was clicked and when.\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": "Click events returned"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/system.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsSystem",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Operating system breakdown",
        "description": "Returns the breakdown of opens by operating system (Windows, macOS, iOS,\nAndroid, Linux, etc.) for a given campaign.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "OS breakdown returned"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/emailSoftware.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsEmailSoftware",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Email client breakdown",
        "description": "Returns the breakdown of opens by email client (Gmail, Outlook, Apple Mail,\nThunderbird, etc.) for a given campaign.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Email client breakdown returned"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/stats/bounce.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsBounce",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Bounce log",
        "description": "Returns the list of bounced recipients (hard bounces, soft bounces, spam\ncomplaints) for a campaign, with the failure reason for each address.\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": "Bounce events returned",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/suppression/bounces.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listBounces",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List the bounces of the account",
        "description": "Most recent first. The total is in the `X-Total-Count` header.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`hard` or `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Where the bounce comes from: `list`, `contact`, `api` or `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Exact address",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "From this date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Up to this 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 returned",
            "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` must be `hard` or `soft`"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remove a bounce",
        "description": "`Source` and `Type` are required, as returned by `/suppression/bounces`: an `Id` alone is not unique.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` of the 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` or `smtp`"
                  },
                  "Type": {
                    "type": "string",
                    "enum": [
                      "hard",
                      "soft"
                    ],
                    "description": "`hard` or `soft`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bounce removed",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": false
                }
              }
            }
          },
          "400": {
            "description": "`Source` or `Type` missing"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Bounce not found"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/restore.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "restoreBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Put a contact with a hard bounce back in its lists",
        "description": "Only for a hard bounce with the source `contact`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` of the bounce",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contact put back",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": true
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Hard bounce of a contact not found, or address no longer active"
          }
        }
      }
    },
    "/suppression/unsubscribers.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List the unsubscribers of the account",
        "description": "Most recent first. The total is in the `X-Total-Count` header.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "source",
            "in": "query",
            "description": "Where the unsubscribe comes from: `contact`, `list`, `smtp`, `api` or `api3`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Exact address",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "From this date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Up to this 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": "Unsubscribers returned",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/suppression/unsubscribers/add.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "addUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Add an unsubscriber",
        "description": "Without `ListId`, the address is unsubscribed for the whole account. With it, from that unsubscribe list only.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Address to unsubscribe",
                    "example": "stop@example.com"
                  },
                  "Comment": {
                    "type": "string",
                    "description": "Free comment",
                    "example": "Asked by phone"
                  },
                  "ListId": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Unsubscribe list of the account (optional)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `AlreadyUnsubscribed` is true when the address already was.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "AlreadyUnsubscribed": false
                }
              }
            }
          },
          "400": {
            "description": "A valid email is required"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "`ListId` is not an unsubscribe list of this account"
          }
        }
      }
    },
    "/suppression/unsubscribers/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remove an unsubscriber",
        "description": "`Source` is required, as returned by `/suppression/unsubscribers`: an `Id` alone is not unique.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` of the unsubscriber",
            "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` or `api3`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Unsubscriber removed",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Removed": 9012
                }
              }
            }
          },
          "400": {
            "description": "`Source` is required"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "404": {
            "description": "Unsubscriber not found"
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listHistory",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "List sending history",
        "description": "Returns a paginated log of all past email sends.\nFilter by campaign ID or by subject.\nSet `bodyHTML=true` to include the HTML body (automatically limits to 10 per page).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filter by campaign subject (partial, case-insensitive match)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "description": "Return history for a specific campaign only",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "The `MessageBody` field is returned by default. Set to `false` to omit it\n— useful to cut the response size when you only need the metrics.\n",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "History returned successfully",
            "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": "Invalid credentials"
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Upload a contacts file (CSV / XLSX) for bulk import",
        "description": "Upload a CSV or XLSX file to import email contacts into a list.\nThe file is stored and queued for asynchronous processing — the endpoint\nreturns an `ImportJobId` immediately.\n\n**Request type:** `multipart/form-data`\n\n**Required form fields:**\n- `IdClient` (integer) — your Mailpro client ID\n- `ApiKey` (string) — your API key\n- `ListId` (integer) — target list ID. Legacy alias `AddressBookId` is also accepted.\n- `file` (binary) — the CSV or XLSX file to upload\n\n**Optional:**\n- `WebhookUrl` (string) — HTTPS URL called when processing finishes.\n  Receives a JSON payload with the final status (success / failed) and\n  counts of imported / skipped / invalid rows.\n\n**File format:**\n- UTF-8 encoded\n- First row = headers (one must be `Email` — case-insensitive)\n- Other columns map to custom fields of the destination list\n- Max file size: 50 MB\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "ListId",
                  "file"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "ID of the destination list. Legacy alias `AddressBookId` is also accepted.",
                    "example": 101
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV or XLSX file (UTF-8, max 50 MB)"
                  },
                  "WebhookUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Callback URL invoked when processing finishes",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File accepted and queued",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 13,
                  "InternalName": "230575-20260420140221-contacts.csv"
                }
              }
            }
          },
          "400": {
            "description": "No file uploaded or missing ListId"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "500": {
            "description": "Server or storage error"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Webhook management service (separate from the main API host)"
        }
      ],
      "get": {
        "summary": "List webhooks",
        "description": "Returns every webhook configured on the authenticated account.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Webhooks of the account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "items": [
                    {
                      "id": 14,
                      "url": "https://example.com/hooks/mailpro",
                      "description": "Slack integration",
                      "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": "Invalid credentials"
          }
        }
      },
      "post": {
        "summary": "Create a webhook",
        "description": "Creates a new webhook subscription. The response contains a `secret` that\nis **shown only once** — store it immediately, server-side. Use it to\nverify the HMAC signature of every incoming payload.\n\n**Limits**: max 20 webhooks per account, max 50 events per 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": "Slack integration"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created — `secret` is returned only here",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "email.delivered",
                    "email.bounced"
                  ],
                  "description": "Slack integration",
                  "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": "Invalid URL, events list, or limit exceeded"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Webhook management service"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "summary": "Get a webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "The webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found"
          }
        }
      },
      "put": {
        "summary": "Update a webhook",
        "description": "Partial update — only the sent fields are modified.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload"
          },
          "404": {
            "description": "Webhook not found"
          }
        }
      },
      "delete": {
        "summary": "Delete a webhook",
        "description": "Permanently deletes the webhook and its full delivery history.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "description": "Webhook not found"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Webhook management service"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Send a test event",
        "description": "Queues an immediate `ping` event (or any other event type via the\n`eventType` body field) to your endpoint. Useful to verify reachability\nand signature verification before relying on real events.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventType": {
                    "type": "string",
                    "default": "ping"
                  }
                }
              },
              "example": {
                "eventType": "ping"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Event queued for dispatch",
            "content": {
              "application/json": {
                "example": {
                  "deliveryId": 1234,
                  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
                  "eventType": "ping"
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found"
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Webhook management service"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Rotate the HMAC secret",
        "description": "Generates a new HMAC secret and invalidates the old one immediately.\nThe new secret is returned **once** in the response — store it. Every\ndelivery from this point on will be signed with the new secret.\n\nUse this if you suspect your secret has been compromised.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "New secret (visible once)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Webhook management service"
        }
      ],
      "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": "Pagination cursor (= last delivery ID seen). Returns deliveries with `id < cursor`."
        }
      ],
      "get": {
        "summary": "List delivery attempts",
        "description": "Returns the history of dispatch attempts for this webhook (30-day retention).\nUseful for debugging — which events were sent, status codes received,\nretry counts, error messages.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array of delivery attempts (newest first)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Webhook management service"
        }
      ],
      "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": "Replay a delivery",
        "description": "Queues a fresh delivery attempt with the same payload as the original.\nUseful to re-trigger a failed delivery after fixing your endpoint.\nA NEW `Webhook_Delivery` row is created (the original is preserved\nfor audit). The replay goes through the standard retry policy\n(same backoff schedule, same 10-failure auto-disable rule).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Replay queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook or delivery not found"
          }
        }
      }
    }
  }
}