{
  "openapi": "3.0.3",
  "info": {
    "title": "API Email Mailpro™ v2",
    "version": "2",
    "description": "L'API Email v2 di Mailpro™ ti consente di gestire programmaticamente liste di contatti, modelli\nemail, indirizzi mittente e campagne — e di inviare sia email di massa sia transazionali.\n\n## Autenticazione\n\nOgni endpoint accetta **tre metodi di autenticazione**. Utilizza quello più adatto\nal tuo stack.\n\n- **OAuth 2.0** — token con scope, revocabili, per applicazioni di terze parti e\n  piattaforme di integrazione (Zapier, Make, n8n). È l'unico metodo che puoi affidare a\n  un terzo. **I token OAuth sono controllati per scope su ogni endpoint** (vedi sotto).\n- **Bearer JWT** (legacy) — un token HMAC ottenuto con `POST /token`, senza scope.\n- **IdClient + ApiKey** (legacy) — ID cliente + chiave API.\n\n> Il Bearer JWT legacy e IdClient+ApiKey continuano a funzionare senza modifiche e **non** sono\n> soggetti agli scope. Solo i token di accesso OAuth 2.0 sono soggetti ai controlli di scope per endpoint\n> indicati su ogni operazione qui sotto.\n\n### Metodo 1 — OAuth 2.0 (consigliato per le integrazioni)\n\nMailpro gestisce **un unico** server di autorizzazione OAuth 2.0 per tutte le sue API, su una\nsuperficie unica e indipendente dalla versione: **`https://api.mailpro.com/oauth/`**. Non esiste\nun endpoint OAuth per versione — ottieni un token da `/oauth/token` e lo\n**stesso** token funziona su questa API Email v2, su CRM v3 e su SMS. Gli\nendpoint che può chiamare dipendono dagli **scope** del token, non dall'URL di base\ndell'API. Emittente (claim `iss`): `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Autorizzazione | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / rinnovo | `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\nGrant: `authorization_code` **+ PKCE (S256, obbligatorio)**, `client_credentials`,\n`refresh_token` (rotazione). Durata del token di accesso: **20 min**; token di aggiornamento: **30 giorni**\n(scorrevoli, monouso); codice di autorizzazione: **60 s**.\n\n**Avvio rapido — ottenere un token e chiamare questa API** (sostituisci i valori; non\nfare mai il commit di un vero 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\nChiama poi questa API con `Authorization: Bearer ACCESS_TOKEN`. Lo stesso token\nfunziona sulle API CRM v3 e SMS. Un token a cui manca lo scope richiesto da un\nendpoint riceve **403 `insufficient_scope`**. Percorso completo e catalogo degli scope:\nvedi la documentazione dell'API **CRM v3** › Autenticazione. Scope utili per l'email:\n`email:send`, `email:read`, `email:templates:read`, `email:templates:write`,\n`contacts:read`, `contacts:write`, `account:read`.\n\n### Metodo 2 — Bearer JWT (legacy)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nOttieni un token tramite `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\nLo stesso token è valido anche sulla CRM API v3 e sulla SMS API —\nautenticati una sola volta, chiama qualsiasi API. I token hanno una validità predefinita di **30 giorni**;\nutilizza `grant_type=refresh_token` per rinnovarli senza doverti autenticare nuovamente. Senza scope\n— preferisci OAuth 2.0 per le integrazioni installabili.\n\n### Metodo 3 — IdClient + ApiKey\n\nDue credenziali:\n\n| Parametro  | Tipo    | Descrizione |\n|------------|---------|-------------|\n| `IdClient` | integer | Il tuo ID cliente Mailpro numerico, reperibile in **Impostazioni → Accesso API** |\n| `ApiKey`   | string  | La tua chiave API, reperibile in **Impostazioni → Accesso API** |\n\nInvialle in uno di questi punti — scegli uno:\n\n1. **Header HTTP (consigliato)** — `IdClient: 12345` e `ApiKey: a1b2c3d4-…`.\n   Gli URL vengono registrati nei log dei web server, dei CDN e dei proxy, quindi una chiave inserita nella query string\n   può finire nei log di accesso. Gli header non vengono registrati.\n2. **Query string (legacy, ancora funzionante)** — `?IdClient=12345&ApiKey=…`.\n   Mantenuto per retrocompatibilità con le integrazioni esistenti. Passa agli\n   header non appena possibile.\n3. **Form body (solo POST)** — `IdClient=12345&ApiKey=…` in\n   `application/x-www-form-urlencoded`.\n\nSe fornisci le credenziali in più punti, **prevale l'header**.\n\n### Controllo degli scope OAuth per endpoint (Email v2)\n\nPer i token emessi da OAuth, ogni gruppo di endpoint richiede uno scope (l'autenticazione\nlegacy ne è esente). Ogni operazione indica il proprio scope sotto **Authorization**. Riepilogo:\n\n| Endpoint | Scope richiesto |\n|----------|-----------------|\n| `/send/*` (campagne, transazionale, pianificazione, test — tranne `/send/{IdSend}/status`) | `email:send` |\n| `/stats/*` (tranne `/stats/del`), `/history/list`, `/send/{IdSend}/status` | `email:read` |\n| `/message/*`, `/senderEmail/*` (lettura) | `email:templates:read` |\n| `/message/*`, `/senderEmail/*` (add/edit/del), `/stats/del` | `email:templates:write` |\n| `/list/list`, `/email/list` | `contacts:read` |\n| `/list/{add,edit,del}`, `/email/{add,addSingle,edit,del}`, `/import/upload` | `contacts:write` |\n| `/account/*` | `account:read` |\n\nUn rifiuto per scope restituisce **403** con\n`{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }`.\n\n## Formato della risposta\n\nTutti gli endpoint supportano `json` (predefinito) e `xml`. Specifica il formato nell'URL:\n- `/email/list.json`\n- `/email/list.xml`\n\n## Paginazione\n\n**Stessa regola sulle tre API Mailpro** (Email v2, CRM v3, SMS): **5.000 elementi per pagina,\nper impostazione predefinita e al massimo.**\n- `numberOfRecords` — elementi per pagina. Assente, `0` o oltre 5.000 = 5.000.\n- `pageNumber` — numero di pagina a partire da 1 (predefinito 1).\n- Entrambi sono accettati come parametro di query **o** come header HTTP.\n- Una pagina piena significa che potrebbero essercene altre: richiedi la pagina successiva finché\n  non ricevi una pagina incompleta.\n- Le pagine sono stabili: la stessa chiamata restituisce gli stessi elementi, nello stesso ordine,\n  finché i dati non cambiano nel frattempo.\n- Eccezione: gli elenchi di messaggi e di cronologia con il loro HTML (`bodyHTML=true`) restituiscono 10 elementi per pagina.\n- `/email/list` aggiunge `X-Total-Count` (il totale reale) e `X-Truncated: true` quando restano contatti\n  oltre la pagina.\n\n**Parametri sconosciuti**: vengono ignorati, mai rifiutati. Quando una richiesta contiene un parametro che l'API\nnon riconosce, la risposta include `X-Ignored-Parameters` (i nomi) e `X-Documentation` (un link a questa\npagina), così un errore di battitura non passa inosservato.\n\n## Risposte di errore\n\n| HTTP | Significato |\n|------|---------|\n| 400  | Richiesta non valida — parametro obbligatorio mancante o non valido |\n| 401  | Non autorizzato — `IdClient` o `ApiKey` non validi |\n| 403  | Vietato — limite dell'account raggiunto (ad es. numero massimo di liste) |\n| 404  | Non trovato — la risorsa richiesta non esiste |\n| 500  | Errore interno del server |\n\nErrori derivanti da regole di business:\n- `\"Not enough credit available.\"` → 403 — il tuo account non dispone più di crediti email\n- `\"Email address unsubscribed.\"` → 400 — il destinatario si è disiscritto\n\n## Tracciamento della consegna (email transazionali)\n\nOgni email inviata **singolarmente** (`POST /send/sendmail`, la CRM API v3, il relay SMTP o un'automazione) riceve un identificativo. Può essere seguita finché il server del destinatario non la accetta o la rifiuta. Le campagne non sono coperte qui: usate le statistiche.\n\n1. **Inviate**: la risposta di `POST /send/sendmail.{format}` contiene l'identificativo dell'invio.\n2. **Ricevete il risultato** (consigliato): gli eventi webhook `email.delivered` ed `email.bounced` inviano lo stato finale al vostro server non appena è noto, senza alcuna interrogazione.\n3. **Oppure interrogate**: `GET /send/{IdSend}/status.{format}` restituisce lo stato attuale (tabella sotto).\n\n| `status` | Significato | Finale? |\n|---|---|---|\n| `queued` | Accettata, in attesa di invio. | no |\n| `scheduled` | Pianificata per più tardi (`DatePlanned`). | no |\n| `sent` | Consegnata dai nostri server, ancora nessuna risposta dal server del destinatario. | no |\n| `delivered` | Accettata dal server del destinatario (`DiagCode` = la sua risposta SMTP). | **sì** |\n| `bounced` | Rifiutata. `BounceType`: `hard` = indirizzo non valido o rifiuto definitivo; `soft` = rifiuto dopo nuovi tentativi (casella piena, server irraggiungibile…). | **sì** |\n| `not_found` | Identificativo sconosciuto o che non appartiene al vostro account. | **sì** |\n\n**Interrogare senza andare in loop**\n\n- Smettete di interrogare non appena lo stato è **finale**: non cambierà più.\n- Prima interrogazione non prima di **5 minuti** dall'invio: `delivered` compare circa 5 minuti dopo la consegna.\n- Poi **al massimo un'interrogazione ogni 15 minuti**.\n- Se interrogate un invio non finale prima di 15 minuti, ricevete la stessa risposta con l'intestazione `Retry-After` (i secondi da attendere), e la chiamata non conta nella vostra quota.\n- **Al più tardi 48 ore** dopo l'invio, ogni email ha uno stato finale: oltre, non interrogate più.\n- `scheduled`: inutile interrogare prima di `DatePlanned`.\n- **Ogni interrogazione conta nella vostra quota di richieste API.** Seguendo queste regole, un invio costa al massimo 192 richieste (4 all'ora per 48 ore), e molte meno in pratica, poiché ci si ferma allo stato finale. Lo stesso tracciamento via webhook costa un solo evento.\n\nGli stati sono conservati per **365 giorni**.\n\n## Webhook\n\nMailpro™ è in grado di notificare il tuo server in tempo reale quando si verificano determinati eventi sul tuo\naccount (un'email viene recapitata, una campagna termina, un contatto fa bounce, ecc.).\nStile Stripe — il tuo URL riceve una POST firmata in HMAC-SHA256 non appena l'evento\nsi attiva.\n\nOgni evento inviato al vostro webhook conta come 1 richiesta nella vostra quota di richieste API.\n\n### Come funziona\n\n1. **Sottoscrivi** uno o più tipi di evento tramite `POST /webhooks`. La risposta\n   contiene un `secret` mostrato **una sola volta** (stile Stripe / GitHub) — conservalo.\n2. **Mailpro effettua una POST** con un payload JSON firmato verso il tuo URL non appena un evento corrisponde.\n3. **Verifica la firma** lato server con il tuo `secret` (snippet di seguito).\n4. **Rispondi con un codice 200–299** entro 10 secondi. In caso contrario, ritentiamo con backoff\n   esponenziale (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, dopodiché desistiamo).\n\n> **⏱ Ritardo di attivazione** — dopo aver creato, aggiornato o eliminato un webhook, la\n> modifica impiega fino a **10 minuti** per propagarsi su tutti i server dell'API\n> Mailpro. Durante questo intervallo gli eventi potrebbero non corrispondere ancora alla tua nuova sottoscrizione\n> (oppure potrebbero ancora corrispondere a una appena rimossa). È il tempo necessario per\n> aggiornare la cache in memoria delle sottoscrizioni su ogni istanza dell'API.\n\n### Envelope del payload\n\nTutti gli eventi condividono un envelope comune:\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| Campo | Formato | Descrizione |\n|-------|--------|-------------|\n| `id` | `evt_` + 32 hex | ID univoco dell'evento — utilizzalo come chiave di idempotenza sul tuo lato. |\n| `type` | `<domain>.<verb>` | Tipo di evento canonico. |\n| `created` | Secondi Unix UTC | Incluso nella firma HMAC. |\n| `apiVersion` | `\"v2\"` | Quale API Mailpro ha pubblicato l'evento. |\n| `account.id` | int | Il tuo ID cliente Mailpro (= `IdClient`). |\n| `account.name` | string | Il nome del tuo account (utile per il debug lato client). |\n| `data` | object | Payload dell'evento — la forma dipende dal `type` (vedi catalogo qui sotto). |\n\n### Catalogo degli eventi\n\n| Evento | Trigger | Forma di `data` |\n|-------|---------|--------------|\n| `ping` | Test tramite `POST /webhooks/{id}/test` | `{ message }` |\n| `email.processed` | Invio accettato dalla pipeline | `{ messageId, email, campaignId, processedAt }` |\n| `email.delivered` | Un'email **singola** è stata accettata dal server del destinatario — API v2/v3, SMTP o Automation (**non** le campagne). Emesso dal flusso di consegna PowerMTA. | `{ messageId, email, idSending, sendingType, diagCode, deliveredAt }` |\n| `email.opened` | Pixel di tracciamento attivato | `{ messageId, email, campaignId, openedAt, ip, userAgent }` |\n| `email.clicked` | Click su un link tracciato | `{ messageId, email, campaignId, clickedAt, url, ip, userAgent }` |\n| `email.bounced` | Hard o soft bounce | `{ messageId, email, campaignId, bouncedAt, bounceType, reason }` |\n| `email.spam_report` | Reclamo FBL | `{ messageId, email, campaignId, reportedAt }` |\n| `email.unsubscribed` | Click sul link di opt-out | `{ messageId, email, campaignId, unsubscribedAt }` |\n| `email.dropped` | Rifiutato prima dell'invio | `{ messageId, email, campaignId, droppedAt, reason }` |\n| `campaign.started` | Inizio della distribuzione | `{ campaignId, name, totalRecipients, startedAt }` |\n| `campaign.finished` | Tutti i destinatari elaborati | `{ campaignId, name, totalSent, totalFailed, finishedAt }` |\n| `credits.low` | Saldo dei crediti email al di sotto della soglia di allerta | `{ remaining, threshold }` |\n\nSottoscrivi tutti gli eventi di questa API passando `[\"*\"]` nell'array `events`.\n\n### Firma HMAC\n\nOgni POST include un header `X-Mailpro-Signature`:\n\n```\nX-Mailpro-Signature: t=1748194800,v1=7f9ac2b6e4d1c8a3...\nX-Mailpro-Event-Id:  evt_8f3a9b2c4d1e5f6789abcdef01234567\nX-Mailpro-Event-Type: email.delivered\nX-Mailpro-Attempt:   1\n```\n\nPer verificare:\n1. Estrai `t` e `v1` dall'header.\n2. **Rifiuta** se `|now - t| > 300` (finestra di protezione anti-replay di 5 minuti).\n3. Calcola `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Confronta a tempo costante** `v1` con `expected` (`crypto.timingSafeEqual`,\n   `hash_equals`, `CryptographicOperations.FixedTimeEquals`) — mai con `==`.\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 e disattivazione automatica\n\n| Tentativo | Ritardo prima del successivo |\n|---------|----------------------|\n| 1 → 2 | 10 secondi |\n| 2 → 3 | 1 minuto |\n| 3 → 4 | 5 minuti |\n| 4 → 5 | 30 minuti |\n| 5 → 6 | 2 ore |\n| 6 → 7 | 6 ore |\n| 7 | abbandonato (recapito contrassegnato come `failed`) |\n\nDopo **10 fallimenti consecutivi** sullo stesso webhook, viene **disattivato\nautomaticamente** (`isActive: false`) e ricevi un'email di notifica. Riattivalo\ncon `PUT /webhooks/{id}` una volta corretto il tuo endpoint.\n\n### Successo = HTTP 2xx\n\nConsideriamo il tuo webhook come riuscito solo se restituisci uno stato compreso tra `200–299`.\nQualsiasi 3xx/4xx/5xx oppure un timeout (> 10 s) viene considerato un fallimento e attiva i retry.\nSe il tuo endpoint è definitivamente fuori uso, restituisci esplicitamente `410 Gone` — i retry\nverranno comunque effettuati, ma la causa del fallimento sarà più chiara nel tuo log di recapito.\n\n### Limiti\n\n| Limite | Valore |\n|-------|-------|\n| Webhook per account | 20 |\n| Eventi sottoscritti per webhook | 50 |\n| Dimensione massima del payload | 256 KB |\n| Timeout HTTP per tentativo | 10 secondi |\n| Conservazione dello storico dei recapiti | 30 giorni |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/v2",
      "description": "Produzione"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token JWT Bearer ottenuto da `POST /v2/token` (form-encoded, password\ngrant). Lo stesso token è valido anche sulla CRM API v3 e sulla SMS\nAPI — autentichi una volta, chiami qualsiasi API.\nPassalo come: `Authorization: Bearer <token>`\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Mailpro OAuth 2.0 — il modo moderno per le app di terze parti e le\npiattaforme di integrazione (Zapier, Make, n8n) di agire per conto di un utente\nMailpro con token di accesso scoped e revocabili.\n\n- **authorizationCode + PKCE** (S256, obbligatorio per i client pubblici) — il\n  flusso di consenso \"Connect Mailpro\". Emette un access token + un refresh\n  token rotante.\n- **clientCredentials** — machine-to-machine, senza utente coinvolto.\n\nUn unico server di autorizzazione per tutte le API, sull'endpoint neutro\nrispetto alla versione `https://api.mailpro.com/oauth/` (issuer / claim `iss`\n`https://api.mailpro.com/oauth/`). Gli access token sono JWT RS256\n(verificali con il JWKS su `https://api.mailpro.com/oauth/.well-known/jwks`);\nTTL **20 minuti**. I refresh token sono validi **30 giorni** (sliding) e\n**monouso** (ruotati a ogni refresh). I codici di autorizzazione vivono\n**60 secondi**.\n\nLo stesso access token OAuth è accettato da tutte e tre le API Mailpro\n(CRM v3, Email v2, SMS) — autenticati una volta, chiama qualsiasi API; l'accesso\nè governato dagli scope del token, non dall'URL base dell'API. L'autenticazione\nlegacy (Bearer JWT / IdClient+ApiKey) continua a funzionare invariata e NON\nè vincolata agli scope.\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": "Il tuo ID client Mailpro numerico — trasporto **preferito** (header HTTP).\nGli URL vengono registrati dai web server, da Cloudflare e dai proxy, perciò\nle credenziali in query-string possono trapelare nei log di accesso. Gli header non vengono registrati.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "ApiKey",
        "description": "La tua chiave API (GUID) — trasporto **preferito** (header HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "IdClient",
        "description": "Il tuo ID client Mailpro numerico — **legacy**, mantenuto per retrocompatibilità.\nQuando puoi, passa all'header `IdClient`.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "ApiKey",
        "description": "La tua chiave API (GUID) — **legacy**, mantenuta per retrocompatibilità.\n"
      }
    },
    "parameters": {
      "format": {
        "name": "format",
        "in": "path",
        "required": true,
        "description": "Formato della risposta",
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "xml"
          ],
          "default": "json"
        },
        "example": "json"
      },
      "numberOfRecords": {
        "name": "numberOfRecords",
        "in": "query",
        "description": "Elementi per pagina — 5.000 predefiniti e al massimo (vedi Paginazione).",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 50
      },
      "pageNumber": {
        "name": "pageNumber",
        "in": "query",
        "description": "Numero di pagina (1-based). Il valore predefinito è 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Token di accesso JWT — usalo come `Authorization: Bearer <token>` nelle richieste successive."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Durata del token in secondi",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "ID client dell'utente autenticato",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Token per ottenere un nuovo token di accesso senza autenticarsi di nuovo"
          },
          "application": {
            "type": "string",
            "description": "Nome dell'integrazione (solo per concessioni di terze parti)",
            "nullable": true
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "ListID": {
            "type": "integer",
            "description": "Identificatore univoco della lista",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias legacy** — stesso valore di `ListID`. Restituito per retrocompatibilità con i client più vecchi.",
            "example": 101
          },
          "Title": {
            "type": "string",
            "description": "Nome visualizzato della lista",
            "example": "Newsletter — France"
          },
          "Type": {
            "type": "integer",
            "description": "`0` = lista contatti standard, `1` = lista nera (per la gestione delle disiscrizioni)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "NumberEmails": {
            "type": "integer",
            "description": "Numero totale di contatti in questa lista",
            "example": 4521
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "description": "Data e ora di creazione della lista",
            "example": "2025-01-15T10:30:00"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "IDMessage": {
            "type": "integer",
            "description": "Identificatore univoco del modello di messaggio",
            "example": 501
          },
          "Subject": {
            "type": "string",
            "description": "Oggetto dell'email",
            "example": "Spring Newsletter — April 2026"
          },
          "Language": {
            "type": "string",
            "description": "Codice lingua utilizzato per la localizzazione del link di disiscrizione",
            "example": "EN"
          },
          "LinkAlign": {
            "type": "string",
            "description": "Allineamento orizzontale del link di disiscrizione",
            "enum": [
              "left",
              "center",
              "right"
            ],
            "example": "center"
          },
          "LinkUp": {
            "type": "integer",
            "description": "Posizione del link di disiscrizione — `0` = in basso, `1` = in alto",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "BodyHTML": {
            "type": "string",
            "description": "Contenuto HTML completo dell'email (restituito solo quando `bodyHTML=true`)",
            "example": "<h1>Welcome!</h1><p>This is our spring newsletter.</p>"
          },
          "UpdateDate": {
            "type": "string",
            "format": "date-time",
            "description": "Data e ora dell'ultima modifica del modello",
            "example": "2026-03-10T14:22:00"
          }
        }
      },
      "SenderEmail": {
        "type": "object",
        "properties": {
          "IDEmailExp": {
            "type": "integer",
            "description": "Identificatore univoco dell'indirizzo email mittente",
            "example": 201
          },
          "Email": {
            "type": "string",
            "description": "Indirizzo email mittente (deve essere verificato prima dell'uso)",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nome visualizzato come mittente nei client di posta dei destinatari",
            "example": "Your Company Newsletter"
          },
          "IsValid": {
            "type": "boolean",
            "description": "`true` se l'indirizzo email è stato verificato da Mailpro",
            "example": true
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "example": "2025-06-01T09:00:00"
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "IDSend": {
            "type": "integer",
            "description": "Identificatore univoco di questo invio / campagna",
            "example": 3001
          },
          "ListID": {
            "type": "integer",
            "description": "ID della lista dei destinatari utilizzata",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias legacy** — stesso valore di `ListID`.",
            "example": 101
          },
          "IDCampaign": {
            "type": "integer",
            "description": "ID del record delle statistiche della campagna (se al momento dell'invio è stato impostato Campaign=1)",
            "example": 8001
          },
          "SenderEmail": {
            "type": "string",
            "description": "Indirizzo email del mittente",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nome visualizzato del mittente",
            "example": "Your Company Newsletter"
          },
          "DatePlanned": {
            "type": "string",
            "format": "date-time",
            "description": "Data e ora di invio pianificate",
            "example": "2026-04-20T09:00:00"
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Oggetto dell'email",
            "example": "Spring Newsletter — April 2026"
          },
          "NumberCredit": {
            "type": "integer",
            "description": "Numero di crediti email consumati da questo invio",
            "example": 4521
          }
        }
      },
      "HistoryEntry": {
        "type": "object",
        "properties": {
          "IDHistoric": {
            "type": "integer",
            "description": "Identificatore univoco di questa voce della cronologia",
            "example": 9001
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Oggetto dell'email inviata",
            "example": "Spring Newsletter — April 2026"
          },
          "DateSend": {
            "type": "string",
            "format": "date-time",
            "description": "Data e ora di invio dell'email",
            "example": "2026-04-20T09:00:01"
          },
          "NumberSend": {
            "type": "integer",
            "description": "Numero totale di email inviate in questa campagna",
            "example": 4521
          },
          "NumberOpen": {
            "type": "integer",
            "description": "Numero di aperture uniche registrate",
            "example": 1823
          },
          "NumberClick": {
            "type": "integer",
            "description": "Numero di clic unici sui link registrati",
            "example": 342
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "ID del webhook (Mailpro)",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS che riceve gli eventi",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipi di evento sottoscritti",
            "example": [
              "email.delivered",
              "email.bounced",
              "campaign.finished"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Slack integration"
          },
          "is_active": {
            "type": "boolean",
            "description": "Quando è `false`, nessun evento viene consegnato. Disabilitato automaticamente dopo 10 fallimenti consecutivi.",
            "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": "Quando è stato effettuato l'ultimo tentativo di consegna",
            "example": "2026-07-21T18:56:07.653"
          },
          "last_delivery_status": {
            "type": "integer",
            "nullable": true,
            "description": "Stato HTTP restituito dal tuo endpoint nell'ultima consegna",
            "example": 200
          },
          "consecutive_failures": {
            "type": "integer",
            "description": "Azzerato al primo successo; a 10 il webhook viene disattivato automaticamente",
            "example": 0
          }
        }
      },
      "WebhookList": {
        "type": "object",
        "description": "Involucro restituito da `GET /webhooks`.",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "total": {
            "type": "integer",
            "description": "Numero totale di webhook sull'account",
            "example": 2
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS (HTTP rifiutato in produzione)",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "Elenco dei tipi di evento da sottoscrivere (vedi il catalogo sopra). Usa `[\"*\"]` per sottoscriverti a tutti gli eventi di questa 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": "Segreto HMAC. **Mostrato una sola volta qui, mai più.** Memorizzalo lato server.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Aggiornamento parziale — ogni campo è facoltativo.",
        "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": "Imposta `true` per riattivare un webhook disattivato automaticamente una volta corretto l'endpoint."
          }
        }
      },
      "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": "Ottieni un token JWT Bearer per autenticare tutte le altre chiamate API. L'endpoint\n`/token` v2 è un redirect 307 verso l'emittente canonico `/v3/token` —\nil tuo client HTTP segue il redirect in modo trasparente (il metodo POST\ne il body vengono preservati).\n"
    },
    {
      "name": "Account",
      "description": "Verifica il saldo dei crediti email, la quota API mensile e lo stato dell'abbonamento."
    },
    {
      "name": "Lists",
      "description": "Gestisci le liste (liste di contatti). Una lista raggruppa i contatti per campagne di massa.\n**Massimo 1.000 liste per account** (stesso limite sulle tre API Mailpro e nell'app).\n`Type 0` = lista standard. `Type 1` = lista nera (utilizzata per la gestione delle disiscrizioni).\n"
    },
    {
      "name": "Contacts",
      "description": "Gestisci singoli contatti email. I contatti appartengono a una o più liste.\nUsa l'importazione di massa (`/email/add`) per grandi lotti, oppure l'aggiunta di un singolo contatto (`/email/addSingle`)\nper iscrizioni individuali con valori dei campi personalizzati.\n"
    },
    {
      "name": "Messages",
      "description": "Gestisci i modelli email HTML. Un modello di messaggio memorizza l'oggetto dell'email,\nil corpo HTML e la configurazione del link di disiscrizione.\nI modelli vengono riutilizzati tra più campagne.\n"
    },
    {
      "name": "Campaigns",
      "description": "Invia campagne email di massa a una lista e gestisci gli invii pianificati.\nUna campagna utilizza un modello di messaggio e un indirizzo mittente.\n"
    },
    {
      "name": "Transactional",
      "description": "Invia email transazionali singole a destinatari individuali.\nA differenza delle campagne, le email transazionali non richiedono una lista —\npassi direttamente l'email del destinatario e il corpo HTML.\n"
    },
    {
      "name": "Sender Addresses",
      "description": "Elenca e gestisci gli indirizzi email mittenti validati.\nSolo gli indirizzi verificati possono essere utilizzati come indirizzo `From` nelle campagne.\n"
    },
    {
      "name": "Statistics",
      "description": "Accedi alle metriche di performance per campagna: aperture, clic, bounce e altro.\nSono disponibili analisi dettagliate per ora, giorno, paese, OS e client di posta.\n"
    },
    {
      "name": "History",
      "description": "Sfoglia il registro completo di tutti gli invii email passati.\n"
    },
    {
      "name": "Import",
      "description": "Carica un file CSV o XLSX per importare contatti email in una lista in modo massivo.\nIl file viene messo in coda per l'elaborazione asincrona — monitora il completamento tramite\nl'`ImportJobId` restituito o tramite la callback `WebhookUrl` opzionale.\n"
    },
    {
      "name": "Webhooks",
      "description": "Sottoscrivi il tuo server alle notifiche di eventi in tempo reale. Mailpro effettua il POST\ndi un payload JSON firmato con HMAC al tuo URL non appena si verifica l'evento sottoscritto.\nConsulta la sezione \"Webhooks\" nell'introduzione per il catalogo completo degli eventi,\nl'envelope del payload, gli snippet di verifica della firma e la policy di ritentativo.\n"
    },
    {
      "name": "Suppression",
      "description": "Bounce e disiscritti dell'account: elencare, aggiungere, rimuovere."
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getEmailAccessToken",
        "summary": "Ottieni un token di accesso (redirect 307 a /v3/token)",
        "security": [],
        "description": "Ottiene un token JWT Bearer utilizzando le credenziali del client Mailpro.\nPassa l'`access_token` restituito come `Authorization: Bearer <token>` in tutte\nle richieste successive. Lo stesso token è valido anche sulla CRM API v3 e\nsulla SMS API.\n\n> **⚙ Dettaglio implementativo** — `POST /v2/token` è un **redirect 307\n> Temporary Redirect** verso `POST /v3/token` (configurato a livello di\n> rewrite IIS `web.config`). L'HTTP 307 preserva sia il **metodo** (`POST`)\n> sia il **body della richiesta**, perciò qualsiasi client HTTP conforme agli\n> standard segue il redirect in modo trasparente — continui a fare POST su\n> `/v2/token` e ricevi un JWT valido. Non c'è alcuna logica di emissione del token\n> duplicata; l'API Email v2 non emette mai token direttamente.\n\n### Tipi di grant supportati\n| Tipo di grant | Caso d'uso |\n|------------|----------|\n| `password` | Integrazione standard — username + chiave API |\n| `refresh_token` | Rinnova un token di accesso in scadenza senza autenticarsi di nuovo |\n| `client_credentials` | Server-to-server con solo ID client |\n\n### Durata del token\n- Token di accesso: **30 giorni**\n- Refresh token: **90 giorni**\n\nUsa `grant_type=refresh_token` per rinnovare il token di accesso senza\nautenticarsi di nuovo. Memorizza i token lato server (Vault, variabili d'ambiente);\nnon incorporarli mai nel JS del browser né nei binari delle app mobili. Consulta\nla doc `/token` della CRM API v3 per la nota di sicurezza completa.\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": "Il tuo username Mailpro (email). Obbligatorio per il grant `password`.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "La tua chiave API Mailpro (formato GUID). Obbligatoria per il grant `password`.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Refresh token precedente. Obbligatorio per il grant `refresh_token`."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Il tuo ID client Mailpro (intero). Obbligatorio per il grant `client_credentials`.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token emesso con successo. Restituito da `POST /v3/token` dopo il\nfollow 307 trasparente — il tuo client HTTP vede una normale 200 con\nlo stesso shape del body che riceverebbe direttamente dall'endpoint\ntoken v3.\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 verso `POST /v3/token`, emesso dalla regola di rewrite\nIIS in `web.config`. I client HTTP conformi agli standard seguono questo redirect\nautomaticamente preservando il metodo POST originale e il body del form.\nVisibile solo ai client che disabilitano esplicitamente il follow dei redirect\n(ad es. `curl --max-redirs 0`).\n",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "example": "https://api.mailpro.com/v3/token"
              }
            }
          },
          "400": {
            "description": "Credenziali non valide o tipo di grant non supportato",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Credenziali errate",
                    "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": "Ottieni il saldo dei crediti email",
        "description": "Restituisce il saldo dei crediti email rimanenti per il tuo account Mailpro.\nOgni email inviata consuma un credito. I crediti non scadono con l'abbonamento,\nma sono utilizzabili solo finché l'abbonamento è attivo.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo dei crediti restituito con successo",
            "content": {
              "application/json": {
                "example": {
                  "Credits": 48500
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/account/subscriptionEndDate.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSubscriptionEndDate",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ottieni la data di scadenza dell'abbonamento",
        "description": "Restituisce la data di scadenza dell'abbonamento Mailpro corrente.\nDopo la data di scadenza, gli invii sono bloccati finché l'abbonamento non viene rinnovato.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Data di scadenza dell'abbonamento restituita con successo",
            "content": {
              "application/json": {
                "example": {
                  "SubscriptionEndDate": "2027-01-15T00:00:00"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ottieni la quota API mensile",
        "description": "Restituisce la quota mensile di richieste API per il client autenticato.\n\n**Calcolo della quota:** il limite è calibrato in base ai crediti dell'abbonamento\nemail (tipicamente `subscription_credits × 5`). Per un piano da\n10.000 email/mese, ciò produce un budget mensile di 50.000\nrichieste. Si ripristina alla **data di anniversario dell'abbonamento** (non il\n1° del mese di calendario).\n\n**Cosa consuma i crediti:**\n- Ogni richiesta API autenticata agli endpoint `v2`, `v3` o `sms`.\n- Ogni evento webhook recapitato a un endpoint sottoscritto.\n\n**Cosa è GRATUITO (non consuma crediti):**\n- Gli endpoint `/health`.\n- Le richieste che falliscono con `401`, `403` o `429`.\n- Gli eventi webhook per i client senza sottoscrizione corrispondente.\n\nLa quota è **condivisa tra tutte e 3 le API Mailpro** (`v2`, `v3`, `sms`)\n— un client = un budget mensile sull'intera piattaforma.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot della quota",
            "content": {
              "application/json": {
                "example": {
                  "MonthlyLimit": 50000,
                  "Remaining": 32847,
                  "Used": 17153,
                  "IsFree": false,
                  "RemainedSendsForFree": 0
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Nessun record di quota trovato (account appena creato; la riga verrà creata alla prima richiesta autenticata)."
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listLists",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca tutte le liste",
        "description": "Restituisce tutte le liste dell'account, ordinate per data di creazione (le più recenti per prime)\na meno che non sia impostato `sortByName=true`.\nUsa `type=0` per le liste standard o `type=1` per le liste nere.\n\n> **Alias legacy:** `/addressbook/list.{format}` — stesso endpoint, mantenuto per retrocompatibilità.\n> Le nuove integrazioni dovrebbero usare `/list/*`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleFilter",
            "in": "query",
            "description": "Filtra per titolo (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`0` = solo liste standard, `1` = solo liste nere. Ometti per restituirle tutte.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Imposta a `true` per ordinare i risultati alfabeticamente per titolo",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste restituite con successo.\n\n> La risposta contiene anche un campo duplicato legacy `AddressBookList` (contenuto identico)\n> e ciascun elemento ha un duplicato legacy `AddressBookID` (identico a `ListID`). Le nuove\n> integrazioni dovrebbero ignorarli.\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": "Credenziali non valide"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Crea una lista",
        "description": "Crea una nuova lista (lista di contatti).\nLa lista parte vuota — aggiungi contatti con `/email/add` o `/email/addSingle`.\n**Massimo 1.000 liste per account** (stesso limite sulle tre API Mailpro e nell'app). Restituisce HTTP 422 se il limite è raggiunto.\n\n> **Alias legacy:** `/addressbook/add.{format}` — stesso endpoint, mantenuto per retrocompatibilità.\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": "Nome visualizzato per la nuova lista",
                    "example": "Spring Campaign 2026"
                  },
                  "Type": {
                    "type": "integer",
                    "description": "`0` = lista standard (default), `1` = lista nera",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista creata con successo.\n\n> Viene restituito anche un campo duplicato legacy `AddressBookList` (contenuto identico).\n",
            "content": {
              "application/json": {
                "example": {
                  "Lists": [
                    {
                      "ListID": 103,
                      "Title": "Spring Campaign 2026",
                      "Type": 0,
                      "NumberEmails": 0,
                      "CreationDate": "2026-04-14T12:00:00"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Titolo mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "422": {
            "description": "Limite di liste (1.000) raggiunto"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rinomina una lista",
        "description": "Aggiorna il titolo di una lista esistente.\nI contatti al suo interno non vengono modificati.\n\n> **Alias legacy:** `/addressbook/edit.{format}` — stesso endpoint, mantenuto per retrocompatibilità.\n> Anche il nome del parametro `AddressBookID` è accettato come alias legacy di `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 della lista da rinominare (da `/list/list`). È accettato anche l'alias legacy `AddressBookID`.",
                    "example": 101
                  },
                  "Title": {
                    "type": "string",
                    "description": "Nuovo titolo della lista",
                    "example": "Newsletter — Europe"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista rinominata con successo"
          },
          "400": {
            "description": "ListID o Titolo mancanti"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Lista non trovata"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elimina una lista",
        "description": "Elimina definitivamente una lista **e tutti i contatti in essa contenuti**.\nQuesta azione non può essere annullata.\n\n> **Alias legacy:** `/addressbook/del.{format}` — stesso endpoint, mantenuto per retrocompatibilità.\n> Anche il nome del parametro `AddressBookID` è accettato come alias legacy di `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 della lista da eliminare. È accettato anche l'alias legacy `AddressBookID`.",
                    "example": 101
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista eliminata con successo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "ListID mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Lista non trovata"
          }
        }
      }
    },
    "/email/list.{format}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "listEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca i contatti",
        "description": "Restituisce un elenco paginato dei contatti email dell'account.\nFiltra per lista o per pattern email.\nI risultati sono ordinati alfabeticamente quando `sortByName=true`, altrimenti per ordine di inserimento.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtra per indirizzo email (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "name": "listId",
            "in": "query",
            "description": "Restituisce solo i contatti in questa lista. È accettato anche l'alias legacy `addressBookId`.",
            "schema": {
              "type": "integer"
            },
            "example": 101
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Imposta a `true` per ordinare i risultati alfabeticamente per indirizzo email",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco contatti restituito con successo",
            "content": {
              "application/json": {
                "example": {
                  "Emails": [
                    {
                      "IdEmail": 10001,
                      "Email": "alice@example.com",
                      "Field1": "Alice",
                      "Field2": "Dupont"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/email/add.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Importa contatti (massivo)",
        "description": "Importa uno o più indirizzi email in una lista in un'unica richiesta.\nFornisci gli indirizzi in `EmailList` separati da punti e virgola.\n\n**Esempio:** `alice@example.com;bob@example.com;carol@example.com`\n\nQuesto endpoint importa solo gli indirizzi email. Per impostare anche i valori dei campi personalizzati,\nusa invece `/email/addSingle` per ciascun contatto.\n\nGli indirizzi precedentemente disiscritti vengono saltati silenziosamente a meno che non sia impostato `Force=1`.\n\n**Selezione della lista:** fornisci `ListId` (o il suo alias legacy `AddressBookId`). Almeno uno è obbligatorio.\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 della lista di destinazione. È accettato anche l'alias legacy `AddressBookId`.",
                    "example": 101
                  },
                  "EmailList": {
                    "type": "string",
                    "description": "Indirizzi email da importare separati da punti e virgola",
                    "example": "alice@example.com;bob@example.com;carol@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Imposta a `1` per reimportare indirizzi precedentemente disiscritti.\nDefault: `0` (gli indirizzi disiscritti vengono saltati).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contatti importati con successo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "3 contacts imported"
                }
              }
            }
          },
          "400": {
            "description": "EmailList mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/email/addSingle.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addSingleEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiungi un singolo contatto",
        "description": "Aggiunge un contatto a una lista con valori dei campi personalizzati facoltativi.\n\n`Field1` fino a `Field25` corrispondono alle definizioni delle colonne personalizzate della tua lista.\nLa mappatura dipende dall'ordine in cui sono state definite le colonne — controlla le impostazioni della tua lista\nnell'interfaccia Mailpro per vedere quale numero di campo corrisponde a quale colonna\n(ad es. Field1 = Nome, Field2 = Cognome, Field3 = Città…).\n\n**Selezione della lista:** fornisci `ListId` (o il suo alias legacy `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 della lista di destinazione. È accettato anche l'alias legacy `AddressBookId`.",
                    "example": 101
                  },
                  "Email": {
                    "type": "string",
                    "description": "Indirizzo email del nuovo contatto",
                    "example": "alice@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Imposta a `1` per riaggiungere un indirizzo precedentemente disiscritto",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Valore per il campo personalizzato 1 (la mappatura delle colonne dipende dalla tua lista)",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Valore per il campo personalizzato 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Valore per il campo personalizzato 3",
                    "example": "Paris"
                  },
                  "Field4": {
                    "type": "string",
                    "description": "Valore per il campo personalizzato 4"
                  },
                  "Field5": {
                    "type": "string",
                    "description": "Valore per il campo personalizzato 5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contatto aggiunto con successo",
            "content": {
              "application/json": {
                "example": {
                  "EmailId": 10002,
                  "Email": "alice@example.com",
                  "Field1": "Alice",
                  "Field2": "Dupont",
                  "ListID": 101
                }
              }
            }
          },
          "400": {
            "description": "Email mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/email/edit.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "editEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiorna un contatto",
        "description": "Aggiorna l'indirizzo email e/o i valori dei campi personalizzati di un contatto esistente.\nIdentifica il contatto tramite `EmailId` (da `/email/list`).\nSia `EmailId` sia `Email` sono obbligatori.\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 del contatto da aggiornare (da `/email/list`)",
                    "example": 10001
                  },
                  "Email": {
                    "type": "string",
                    "description": "Nuovo indirizzo email per il contatto",
                    "example": "alice.updated@example.com"
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Nuovo valore per il campo personalizzato 1",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Nuovo valore per il campo personalizzato 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Nuovo valore per il campo personalizzato 3"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contatto aggiornato con successo"
          },
          "400": {
            "description": "EmailId o Email mancanti"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Contatto non trovato"
          }
        }
      }
    },
    "/email/del.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "deleteEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elimina un contatto",
        "description": "Elimina definitivamente un contatto tramite il suo identificatore univoco.",
        "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 del contatto da eliminare (da `/email/list`)",
                    "example": 10001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contatto eliminato con successo"
          },
          "400": {
            "description": "EmailId mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Contatto non trovato"
          }
        }
      }
    },
    "/message/list.{format}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca i modelli di messaggio",
        "description": "Restituisce i modelli email HTML salvati per l'account.\nPer impostazione predefinita, il corpo HTML **non** è incluso nella risposta per mantenere ridotti i payload.\nImposta `bodyHTML=true` per includerlo (limita automaticamente i risultati a 10 per pagina).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectFilter",
            "in": "query",
            "description": "Filtra per oggetto (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Imposta a `true` per includere il corpo HTML completo in ogni risultato.\nQuando è `true`, i risultati vengono automaticamente limitati a 10 per pagina indipendentemente da `numberOfRecords`.\n",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Modelli di messaggio restituiti con successo",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/message/add.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "addMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Crea un modello di messaggio",
        "description": "Crea un nuovo modello email HTML.\nIl modello memorizza l'oggetto, il corpo HTML e le impostazioni del link di disiscrizione.\nUna volta creato, usa l'`IDMessage` restituito quando avvii una campagna.\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": "Oggetto dell'email (massimo 255 caratteri)",
                    "example": "Spring Newsletter — April 2026"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenuto HTML completo del corpo dell'email",
                    "example": "<h1>Spring is here!</h1><p>Check out our latest offers.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Codice lingua per la localizzazione del link di disiscrizione (ad es. `EN`, `FR`, `DE`)",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "description": "Allineamento orizzontale del link di disiscrizione",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "description": "Posizione del link di disiscrizione — `0` = in fondo all'email, `1` = in alto",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modello di messaggio creato con successo",
            "content": {
              "application/json": {
                "example": {
                  "IDMessage": 502,
                  "Subject": "Spring Newsletter — April 2026",
                  "Language": "EN",
                  "LinkAlign": "center",
                  "LinkUp": 0
                }
              }
            }
          },
          "400": {
            "description": "Campo obbligatorio mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/message/edit.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "editMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiorna un modello di messaggio",
        "description": "Aggiorna il contenuto e i metadati di un modello di messaggio esistente.",
        "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 del modello di messaggio da aggiornare (da `/message/list`)",
                    "example": 501
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Nuovo oggetto dell'email",
                    "example": "Spring Newsletter — April 2026 (revised)"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Nuovo contenuto HTML del corpo dell'email",
                    "example": "<h1>Spring is here!</h1><p>Updated content.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Codice lingua per la localizzazione del link di disiscrizione",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modello di messaggio aggiornato con successo"
          },
          "400": {
            "description": "Campo obbligatorio mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Modello di messaggio non trovato"
          }
        }
      }
    },
    "/message/del.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "deleteMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elimina un modello di messaggio",
        "description": "Elimina definitivamente un modello di messaggio tramite il suo identificatore univoco.\nI modelli utilizzati da campagne pianificate in attesa non possono essere eliminati.\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 del modello di messaggio da eliminare (da `/message/list`)",
                    "example": 501
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modello di messaggio eliminato con successo"
          },
          "400": {
            "description": "MessageId mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Modello di messaggio non trovato"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca le campagne pianificate",
        "description": "Restituisce l'elenco delle campagne email pianificate e recentemente elaborate.\nI risultati sono ordinati per data di invio pianificata (la più recente per prima).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtra per oggetto della campagna (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco delle campagne restituito con successo",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/send/campaign.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Avvia una campagna",
        "description": "Pianifica o invia immediatamente una campagna email a una lista\nutilizzando un modello di messaggio salvato e un indirizzo mittente.\n\n**Obbligatorio:**\n- `IDMessage` — il modello da inviare (da `/message/list`)\n- `IDEmailExp` — l'indirizzo mittente da utilizzare (da `/senderEmail/list`)\n- `ListId` — la lista dei destinatari (da `/list/list`). È accettato anche l'alias legacy `IDAddressBook`.\n\n**Pianificazione:** imposta `DatePlanned` su una data/ora ISO 8601 futura per pianificare l'invio.\nOmetti `DatePlanned` per inviare immediatamente.\n\n**Tracciamento delle statistiche:** imposta `Campaign=1` e fornisci un `TitleCampaign` per abilitare\nil tracciamento di aperture/clic/bounce nella sezione Statistiche.\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 della lista dei destinatari (da `/list/list`). È accettato anche l'alias legacy `IDAddressBook`.",
                    "example": 101
                  },
                  "IDMessage": {
                    "type": "integer",
                    "description": "ID del modello di messaggio da inviare (da `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID dell'indirizzo email mittente da utilizzare (da `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDUnsubscribeList": {
                    "type": "integer",
                    "description": "Lista utilizzata per raccogliere i contatti disiscritti (lista nera).\nÈ accettato anche l'alias legacy `IDUnsubscribeAddressBook`.\n",
                    "example": 102
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Data/ora di invio pianificata (ISO 8601). Ometti per inviare immediatamente.",
                    "example": "2026-04-20T09:00:00"
                  },
                  "Campaign": {
                    "type": "integer",
                    "description": "Imposta a `1` per tracciare questo invio come campagna denominata nelle statistiche",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 1
                  },
                  "TitleCampaign": {
                    "type": "string",
                    "description": "Titolo della campagna mostrato nelle statistiche (obbligatorio quando `Campaign=1`)",
                    "example": "Spring Newsletter April 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campagna pianificata o inviata con successo.\n\n> La risposta restituisce anche gli alias legacy `AddressBookID` e `UnsubscribeAddressBookID`\n> (identici a `ListID` / `UnsubscribeListID`). Le nuove integrazioni dovrebbero ignorarli.\n",
            "content": {
              "application/json": {
                "example": {
                  "send": {
                    "IDSend": 3002,
                    "ListID": 101,
                    "UnsubscribeListID": 102,
                    "IDCampaign": 8001,
                    "SenderName": "Your Company Newsletter",
                    "SenderEmail": "newsletter@yourcompany.com",
                    "DatePlanned": "2026-04-20T09:00:00",
                    "SubjectMessage": "Spring Newsletter — April 2026",
                    "NumberCredit": 4521
                  }
                }
              }
            }
          },
          "400": {
            "description": "IDMessage o IDEmailExp mancanti"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "403": {
            "description": "Crediti email insufficienti"
          },
          "404": {
            "description": "Lista, messaggio o mittente non trovati"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "deleteCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annulla o elimina una campagna",
        "description": "Annulla l'invio di una campagna **pianificata in attesa** o elimina una campagna **completata**.\nSolo gli invii pianificati per il futuro possono essere annullati — gli invii in corso non possono essere fermati.\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 dell'invio della campagna da annullare o eliminare (da `/send/list`)",
                    "example": 3001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campagna annullata o eliminata con successo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Campaign Deleted"
                }
              }
            }
          },
          "400": {
            "description": "IdSend mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Campagna non trovata"
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listScheduledCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca le mie campagne email pianificate",
        "description": "Restituisce le campagne email e gli invii singoli pianificati per una data futura che\nnon sono ancora stati recapitati. Utile prima di chiamare `/cancel` o `/reschedule`.\nI record sono ordinati per `DatePlanned` crescente.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco delle campagne / invii pianificati.\n\n> Ogni record include anche gli alias legacy `AddressBookID` e\n> `UnsubscribeAddressBookID` (identici a `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": "Credenziali non valide"
          }
        }
      }
    },
    "/send/{IdSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "cancelScheduledCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annulla una campagna / invio pianificato",
        "description": "Annulla un invio email pianificato (campagna o singolo) che non è ancora stato recapitato.\nSe l'invio è già stato effettuato (o non esiste / appartiene a un altro client),\nrestituisce **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Invio annullato",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 5001
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "409": {
            "description": "Già recapitato o non trovato"
          }
        }
      }
    },
    "/send/{IdSend}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "rescheduleCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ripianifica una campagna / invio pianificato",
        "description": "Aggiorna la `DatePlanned` di un invio email pianificato. La nuova data deve essere\n**futura** e **entro 90 giorni**.\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": "Invio ripianificato",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSend": 5001,
                  "NewPlanDate": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "PlanDate mancante o non valida"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "409": {
            "description": "Già recapitato, non trovato o nuova data fuori intervallo (deve essere futura ed entro 90 giorni)"
          }
        }
      }
    },
    "/send/mail/scheduled.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "listScheduledMails",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca le email singole pianificate",
        "description": "Restituisce le email singole inviate con `/send/sendmail` e una data futura, non ancora partite. Le campagne sono elencate da `/send/scheduled`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Email pianificate restituite",
            "content": {
              "application/json": {
                "example": {
                  "scheduledMails": [
                    {
                      "IdSingleSend": 880123,
                      "Email": "jane@example.com",
                      "Subject": "Your invoice",
                      "DatePlanned": "2026-12-01T09:00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "cancelMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annulla un'email singola pianificata",
        "description": "Annulla l'email finché non è partita.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` restituito da `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email annullata",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 880123
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "409": {
            "description": "Invio non trovato o già partito"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/reschedule.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "rescheduleMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ripianifica un'email singola pianificata",
        "description": "Cambia la data di invio. La nuova data deve essere futura ed entro 90 giorni. È accettato anche `PATCH`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` restituito da `/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": "Nuova data di invio (ISO 8601)",
                    "example": "2026-12-15T09:00:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email ripianificata",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSingleSend": 880123,
                  "NewPlanDate": "2026-12-15T09:00:00"
                }
              }
            }
          },
          "400": {
            "description": "Data mancante o non valida"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "409": {
            "description": "Invio non trovato, già partito o data fuori dai limiti"
          }
        }
      }
    },
    "/send/sendingTest.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendTestEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Invia un'email di test",
        "description": "Invia un'anteprima di un modello di messaggio a un destinatario specificato per la revisione\nprima di avviare la campagna reale.\nIl mittente, il modello e il destinatario di test sono tutti identificati dai loro ID.\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 del modello di messaggio di cui visualizzare l'anteprima (da `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExpFrom": {
                    "type": "integer",
                    "description": "ID dell'indirizzo mittente da utilizzare (da `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDEmailExpTo": {
                    "type": "integer",
                    "description": "ID dell'indirizzo mittente destinatario — l'email di test viene inviata a questo indirizzo",
                    "example": 202
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email di test inviata con successo",
            "content": {
              "application/json": {
                "example": {
                  "SendingTest": {
                    "IdSendingTest": 7001,
                    "ToEmail": "test@yourcompany.com",
                    "FromEmail": "newsletter@yourcompany.com",
                    "SenderName": "Your Company Newsletter"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Campo obbligatorio mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/sendmail.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "sendTransactionalEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Invia un'email transazionale",
        "description": "Invia un'email transazionale singola a uno o più destinatari.\nA differenza delle campagne, questo endpoint non richiede una lista —\nl'indirizzo del destinatario e il corpo HTML vengono passati direttamente.\n\n**Obbligatorio:**\n- `IDEmailExp` — l'ID dell'indirizzo mittente (da `/senderEmail/list`)\n- `EmailData` — destinatario nel formato `email,field1,field2,...,field25` (separati da virgola)\n- `BodyHTML` — il corpo HTML\n- `Subject` — l'oggetto\n\n**Formato EmailData:** `alice@example.com,Alice,Dupont,Parigi`\nIl primo valore è l'indirizzo email; i valori 2–26 corrispondono a Field1–Field25 per\nle variabili di personalizzazione nel tuo modello HTML.\n\n**Più destinatari:** separa più voci `EmailData` con punti e virgola:\n`alice@example.com,Alice;bob@example.com,Bob`\n\n**Pianificazione:** imposta `DatePlanned` su una data/ora ISO 8601 futura, oppure ometti per inviare immediatamente.\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 dell'indirizzo email mittente da utilizzare (da `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinatario nel formato `email,campo1,campo2,...,campo25` (separati da virgola).\nIl primo valore è l'indirizzo email; i restanti sono campi di personalizzazione\nmappati su Field1–Field25 nel tuo modello HTML.\n\n**La parte locale** dell'email (prima della `@`) accetta lettere, cifre e\n`. _ - +` — incluso il sub-addressing RFC 5322 (`user+tag@domain`, es. Gmail,\nFastmail, Proton). Gli altri caratteri speciali consentiti dalla RFC 5322\n(es. `! # $ % & ' * / = ? ^ { | } ~`) e le parti locali tra virgolette **non**\nsono accettati.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenuto HTML completo del corpo dell'email",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Oggetto dell'email (massimo 255 caratteri)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "array",
                    "maxItems": 5,
                    "description": "Allegati facoltativi — invia la richiesta come `multipart/form-data` e aggiungi una parte file per ogni allegato (qualsiasi nome di campo). Fino a **5 file**, **10 MB per file**, **15 MB in totale**. Tipi accettati: PDF, Word, Excel, PowerPoint, immagini (JPG, PNG, GIF, WebP), ZIP, CSV, TXT — i file eseguibili e gli script vengono rifiutati. **Fatturazione:** l'invio mantiene il suo credito abituale, più **1 credito ogni 512 KB di allegati oltre i primi 512 KB** (gli allegati ≤ 512 KB non aggiungono nulla). Tutti gli altri campi di questo endpoint (`ReplyTo`, `ActivateStatistics`, `CustomHeaders`, …) funzionano esattamente come nella variante form-urlencoded.",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (predefinito): gli allegati servono solo per questo invio — sono archiviati fuori dal tuo\naccount, non contano nella tua quota di archiviazione e vengono eliminati automaticamente dopo\n35 giorni. `true`: gli allegati vengono anche conservati nei file del tuo account (cartella\n`Secure/Files/Sending/api`) e contano nella tua quota di archiviazione.\n",
                    "example": false
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID dell'indirizzo email mittente da utilizzare (da `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinatario nel formato `email,campo1,campo2,...,campo25` (separati da virgola).\nIl primo valore è l'indirizzo email; i restanti sono campi di personalizzazione\nmappati su Field1–Field25 nel tuo modello HTML.\n\n**La parte locale** dell'email (prima della `@`) accetta lettere, cifre e\n`. _ - +` — incluso il sub-addressing RFC 5322 (`user+tag@domain`, es. Gmail,\nFastmail, Proton). Gli altri caratteri speciali consentiti dalla RFC 5322\n(es. `! # $ % & ' * / = ? ^ { | } ~`) e le parti locali tra virgolette **non**\nsono accettati.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenuto HTML completo del corpo dell'email",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Oggetto dell'email (massimo 255 caratteri)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "string",
                    "description": "Allegati opzionali come **array JSON** di oggetti `{ \"filename\": …, \"content\": … }`, con `content` **codificato in Base64** (stesso formato dell'API CRM v3). Fino a **5 file**, **10 MB per file** e **15 MB totali** (dopo la decodifica). Sono accettati i formati comuni di documenti e immagini; i file eseguibili e gli script vengono rifiutati. **Fatturazione:** l'invio mantiene il suo 1 credito abituale, più **1 credito ogni 512 KB di allegati oltre i primi 512 KB**. *In alternativa puoi inviare i file come parti `multipart/form-data` (vedi il corpo della richiesta multipart sopra) — funzionano entrambi.*",
                    "example": "[{\"filename\":\"invoice.pdf\",\"content\":\"JVBERi0xLjQK...\"}]"
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (predefinito): gli allegati servono solo per questo invio — sono archiviati fuori dal tuo\naccount, non contano nella tua quota di archiviazione e vengono eliminati automaticamente dopo\n35 giorni. `true`: gli allegati vengono anche conservati nei file del tuo account (cartella\n`Secure/Files/Sending/api`) e contano nella tua quota di archiviazione.\n",
                    "example": false
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Data/ora di invio pianificata (ISO 8601). Ometti per inviare immediatamente.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "ActivateStatistics": {
                    "type": "boolean",
                    "description": "Imposta a `true` per tracciare le aperture e i clic per questa email",
                    "default": false,
                    "example": true
                  },
                  "ReplyTo": {
                    "type": "string",
                    "description": "Indirizzo email reply-to. Se omesso, le risposte vanno all'indirizzo mittente.",
                    "example": "support@yourcompany.com"
                  },
                  "UnsubscriptionLink": {
                    "type": "boolean",
                    "description": "Imposta a `true` per aggiungere un link di disiscrizione al corpo dell'email",
                    "default": false,
                    "example": false
                  },
                  "CustomHeaders": {
                    "type": "string",
                    "description": "Header SMTP aggiuntivi come stringa `key=value` separata da punti e virgola",
                    "example": "X-Campaign-ID=campaign_42;X-Priority=1"
                  },
                  "BodyText": {
                    "type": "string",
                    "description": "Fallback in testo semplice per i client di posta che non visualizzano l'HTML",
                    "example": "Hello Alice, your order has been confirmed."
                  },
                  "List_Unsubscribe": {
                    "type": "string",
                    "description": "Valore per l'header email `List-Unsubscribe` (URL o mailto)",
                    "example": "https://yourcompany.com/unsubscribe?token=abc123"
                  },
                  "List_Unsubscribe_Post": {
                    "type": "string",
                    "description": "Valore per l'header `List-Unsubscribe-Post` (RFC 8058)",
                    "example": "List-Unsubscribe=One-Click"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email transazionale inviata o pianificata con successo",
            "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": "Campo obbligatorio mancante o formato email non valido"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "403": {
            "description": "Crediti email insufficienti"
          },
          "404": {
            "description": "Mittente non trovato o indirizzo email disiscritto"
          }
        }
      }
    },
    "/send/{IdSend}/status.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "getTransactionalStatus",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ottieni lo stato di consegna di un'email transazionale",
        "description": "Restituisce lo stato di consegna attuale di un'email transazionale inviata con `/send/sendmail`. Passa l'`IdSingleSend` restituito da quella chiamata.\n\nValori possibili: `delivered` (accettata dal server del destinatario, vedi `DiagCode`), `bounced` (rifiutata — `BounceType: hard` indirizzo non valido o rifiuto definitivo, `soft` rifiuto dopo nuovi tentativi), `sent` (consegnata al server di posta, ancora nessuna risposta), `scheduled` (non ancora inviata, `DatePlanned` nel futuro) e `queued` (in attesa di invio). `delivered` e `bounced` sono finali: smettete di interrogare. Ogni email ha uno stato finale al più tardi 48 ore dopo l'invio; interrogate al massimo ogni 15 minuti (ogni chiamata conta nella vostra quota API) oppure usate i webhook `email.delivered` / `email.bounced`. Solo il cliente che ha inviato l'email può leggerne lo stato — qualsiasi altro id restituisce 404.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "description": "L'`IdSingleSend` restituito da `/send/sendmail`.",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Stato di consegna attuale",
            "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": "Credenziali non valide"
          },
          "404": {
            "description": "Nessun invio transazionale trovato con questo id per questo cliente"
          }
        }
      }
    },
    "/senderEmail/list.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "listSenderEmails",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca gli indirizzi mittenti validati",
        "description": "Restituisce l'elenco degli indirizzi email mittenti configurati per l'account.\nSolo gli indirizzi con `IsValid: true` possono essere utilizzati per inviare campagne.\nI nuovi indirizzi si aggiungono con `/senderEmail/add` e diventano validi dopo aver cliccato il link nell'email di convalida.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtra per indirizzo email (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "@yourcompany.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Imposta a `true` per ordinare i risultati per nome del mittente alfabeticamente",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Indirizzi mittenti restituiti con successo",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/senderEmail/add.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "addSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiungi un indirizzo mittente",
        "description": "Aggiunge l'indirizzo con gli stessi controlli dell'applicazione e gli invia un'email di convalida. È utilizzabile dopo aver cliccato il link in quell'email. Un account può avere fino a 25 mittenti, convalidati o in attesa.",
        "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": "Indirizzo del mittente",
                    "example": "news@example.com"
                  },
                  "SenderName": {
                    "type": "string",
                    "description": "Nome mostrato ai destinatari",
                    "example": "Example News"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Indirizzo aggiunto. `DomainHasMx` è false quando il dominio non ha un record MX.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true,
                  "DomainHasMx": true
                }
              }
            }
          },
          "400": {
            "description": "`Email` o `SenderName` mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "422": {
            "description": "Indirizzo rifiutato: non valido, già tra i mittenti dell'account, dominio di posta pubblico, nome vietato o limite di 25 raggiunto. Il messaggio indica il motivo."
          },
          "503": {
            "description": "Temporaneamente non disponibile, riprova"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/resendValidation.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "resendSenderValidation",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Invia di nuovo l'email di convalida",
        "description": "Per un indirizzo ancora in attesa di convalida.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID del mittente, da `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email inviata di nuovo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Mittente non trovato"
          },
          "409": {
            "description": "Questo mittente è già convalidato"
          },
          "503": {
            "description": "Temporaneamente non disponibile, riprova"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/authentication.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "getSenderAuthentication",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Controlla il dominio di un mittente (SPF, DKIM, DMARC, MX)",
        "description": "Controlla il dominio in tempo reale nel DNS e restituisce i record da pubblicare. Sola lettura. Il DKIM si attiva nell'applicazione: `DkimSettingsUrl` apre la schermata giusta.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID del mittente, da `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stato del dominio. `Spf.RecommendedRecord` è costruito a partire dal tuo record attuale: pubblicalo solo se `Spf.ChangeNeeded` è 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": "Credenziali non valide"
          },
          "404": {
            "description": "Mittente non trovato"
          },
          "503": {
            "description": "Temporaneamente non disponibile, riprova"
          }
        }
      }
    },
    "/senderEmail/del.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "deleteSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rimuovi un indirizzo mittente",
        "description": "Rimuove un indirizzo email mittente validato dall'account.\nGli indirizzi mittenti utilizzati da campagne pianificate non possono essere eliminati.\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 dell'indirizzo mittente da rimuovere (da `/senderEmail/list`)",
                    "example": 201
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Indirizzo mittente rimosso con successo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "EmailSender Deleted"
                }
              }
            }
          },
          "400": {
            "description": "idEmailExp mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/list.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "listStats",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca le statistiche delle campagne",
        "description": "Restituisce le metriche di performance complessive per tutte le campagne: numero di invii, tasso di apertura,\ntasso di clic, numero di bounce. Filtra per intervallo di date o titolo della campagna.\nI risultati sono ordinati per data di invio (la più recente per prima).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleCampaignFilter",
            "in": "query",
            "description": "Filtra per titolo della campagna (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "spring"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "dateStart",
            "in": "query",
            "description": "Inizio del filtro per intervallo di date (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-01-01T00:00:00"
          },
          {
            "name": "dateEnd",
            "in": "query",
            "description": "Fine del filtro per intervallo di date (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-12-31T23:59:59"
          }
        ],
        "responses": {
          "200": {
            "description": "Statistiche delle campagne restituite con successo",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/byHour.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByHour",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Statistiche per ora",
        "description": "Restituisce la suddivisione oraria delle aperture e dei clic per una campagna specifica.\nUtile per comprendere l'orario di invio ottimale.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID della campagna (da `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Statistiche orarie restituite con successo",
            "content": {
              "application/json": {
                "example": {
                  "ByHour": [
                    {
                      "Hour": 9,
                      "Opens": 823,
                      "Clicks": 142
                    },
                    {
                      "Hour": 10,
                      "Opens": 512,
                      "Clicks": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/byDay.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByDay",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Statistiche per giorno",
        "description": "Restituisce la suddivisione giornaliera delle aperture e dei clic per una campagna specifica.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID della campagna (da `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Statistiche giornaliere restituite con successo"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/del.{format}": {
      "post": {
        "tags": [
          "Statistics"
        ],
        "operationId": "deleteStats",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elimina le statistiche della campagna",
        "description": "Elimina definitivamente tutti i record di statistiche per una determinata campagna.",
        "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 della campagna le cui statistiche eliminare (da `/stats/list`)",
                    "example": 8001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Statistiche della campagna eliminate con successo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Statistic Deleted"
                }
              }
            }
          },
          "400": {
            "description": "IdCampaign mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Campagna non trovata"
          }
        }
      }
    },
    "/stats/country.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsCountry",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Suddivisione per geolocalizzazione",
        "description": "Restituisce la suddivisione per geolocalizzazione delle aperture della campagna — quante aperture sono\nprovenute da ciascun paese.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Suddivisione per paese restituita"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/open.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsOpens",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registro degli eventi di apertura",
        "description": "Restituisce il registro per destinatario degli eventi di apertura per una campagna (una riga per ciascuna apertura).\nUsa `emailFilter` per cercare un destinatario specifico (parziale, 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": "Eventi di apertura restituiti"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/click.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsClicks",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registro degli eventi di clic",
        "description": "Restituisce il registro per destinatario degli eventi di clic per una campagna — incluso\nquale link è stato cliccato e quando.\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": "Eventi di clic restituiti"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/system.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsSystem",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Suddivisione per sistema operativo",
        "description": "Restituisce la suddivisione delle aperture per sistema operativo (Windows, macOS, iOS,\nAndroid, Linux, ecc.) per una determinata campagna.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Suddivisione per OS restituita"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/emailSoftware.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsEmailSoftware",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Suddivisione per client di posta",
        "description": "Restituisce la suddivisione delle aperture per client di posta (Gmail, Outlook, Apple Mail,\nThunderbird, ecc.) per una determinata campagna.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Suddivisione per client di posta restituita"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/stats/bounce.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsBounce",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registro dei rimbalzi",
        "description": "Restituisce l'elenco dei destinatari rimbalzati (rimbalzi hard, rimbalzi soft,\nsegnalazioni di spam) di una campagna, con il motivo dell'errore per ogni indirizzo.\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": "Eventi di rimbalzo restituiti",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/suppression/bounces.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listBounces",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca i bounce dell'account",
        "description": "Prima i più recenti. Il totale è nell'intestazione `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`hard` o `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origine del bounce: `list`, `contact`, `api` o `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Indirizzo esatto",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "A partire da questa data",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Fino a questa data",
            "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": "Bounce restituiti",
            "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` deve essere `hard` o `soft`"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rimuovi un bounce",
        "description": "`Source` e `Type` sono obbligatori, come restituiti da `/suppression/bounces`: un `Id` da solo non è univoco.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` del 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` o `smtp`"
                  },
                  "Type": {
                    "type": "string",
                    "enum": [
                      "hard",
                      "soft"
                    ],
                    "description": "`hard` o `soft`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bounce rimosso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": false
                }
              }
            }
          },
          "400": {
            "description": "`Source` o `Type` mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Bounce non trovato"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/restore.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "restoreBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rimetti nelle sue liste un contatto in hard bounce",
        "description": "Solo per un hard bounce con origine `contact`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` del bounce",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contatto rimesso in lista",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": true
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Hard bounce di un contatto non trovato o indirizzo non più attivo"
          }
        }
      }
    },
    "/suppression/unsubscribers.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca i disiscritti dell'account",
        "description": "Prima i più recenti. Il totale è nell'intestazione `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origine della disiscrizione: `contact`, `list`, `smtp`, `api` o `api3`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Indirizzo esatto",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "A partire da questa data",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Fino a questa data",
            "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": "Disiscritti restituiti",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/suppression/unsubscribers/add.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "addUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiungi un disiscritto",
        "description": "Senza `ListId`, l'indirizzo viene disiscritto per tutto l'account. Con `ListId`, solo da quella lista di disiscrizione.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Indirizzo da disiscrivere",
                    "example": "stop@example.com"
                  },
                  "Comment": {
                    "type": "string",
                    "description": "Commento libero",
                    "example": "Asked by phone"
                  },
                  "ListId": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Lista di disiscrizione dell'account (facoltativo)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fatto. `AlreadyUnsubscribed` è true quando l'indirizzo era già disiscritto.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "AlreadyUnsubscribed": false
                }
              }
            }
          },
          "400": {
            "description": "È richiesto un indirizzo valido"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "`ListId` non è una lista di disiscrizione di questo account"
          }
        }
      }
    },
    "/suppression/unsubscribers/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rimuovi un disiscritto",
        "description": "`Source` è obbligatorio, come restituito da `/suppression/unsubscribers`: un `Id` da solo non è univoco.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` del disiscritto",
            "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` o `api3`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Disiscritto rimosso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Removed": 9012
                }
              }
            }
          },
          "400": {
            "description": "`Source` è obbligatorio"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Disiscritto non trovato"
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listHistory",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca la cronologia degli invii",
        "description": "Restituisce un registro paginato di tutti gli invii email passati.\nFiltra per ID campagna o per oggetto.\nImposta `bodyHTML=true` per includere il corpo HTML (limita automaticamente a 10 per pagina).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtra per oggetto della campagna (corrispondenza parziale, case-insensitive)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "description": "Restituisce la cronologia solo per una campagna specifica",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Imposta a `true` per includere il corpo HTML completo.\nLimita automaticamente i risultati a 10 per pagina.\n",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cronologia restituita con successo",
            "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": "Credenziali non valide"
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Carica un file di contatti (CSV / XLSX) per l'importazione massiva",
        "description": "Carica un file CSV o XLSX per importare contatti email in una lista.\nIl file viene memorizzato e messo in coda per l'elaborazione asincrona — l'endpoint\nrestituisce immediatamente un `ImportJobId`.\n\n**Tipo di richiesta:** `multipart/form-data`\n\n**Campi del form obbligatori:**\n- `IdClient` (intero) — il tuo ID client Mailpro\n- `ApiKey` (stringa) — la tua chiave API\n- `ListId` (intero) — ID della lista di destinazione. È accettato anche l'alias legacy `AddressBookId`.\n- `file` (binario) — il file CSV o XLSX da caricare\n\n**Facoltativo:**\n- `WebhookUrl` (stringa) — URL HTTPS chiamato al termine dell'elaborazione.\n  Riceve un payload JSON con lo stato finale (success / failed) e i\n  conteggi delle righe importate / saltate / non valide.\n\n**Formato del file:**\n- Codificato in UTF-8\n- Prima riga = intestazioni (una deve essere `Email` — case-insensitive)\n- Le altre colonne corrispondono ai campi personalizzati della lista di destinazione\n- Dimensione massima del file: 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 della lista di destinazione. È accettato anche l'alias legacy `AddressBookId`.",
                    "example": 101
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "File CSV o XLSX (UTF-8, massimo 50 MB)"
                  },
                  "WebhookUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL di callback invocato al termine dell'elaborazione",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File accettato e messo in coda",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 13,
                  "InternalName": "230575-20260420140221-contacts.csv"
                }
              }
            }
          },
          "400": {
            "description": "Nessun file caricato o ListId mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "500": {
            "description": "Errore del server o dello storage"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servizio di gestione dei webhook (separato dall'host principale dell'API)"
        }
      ],
      "get": {
        "summary": "Elenca i webhook",
        "description": "Restituisce ogni webhook configurato sull'account autenticato.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array di webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "items": [
                    {
                      "id": 14,
                      "url": "https://example.com/hooks/mailpro",
                      "description": "Integrazione Slack",
                      "is_active": true,
                      "created_at": "2026-07-01T21:09:52.43",
                      "updated_at": "2026-07-21T18:56:08.02",
                      "last_delivery_at": "2026-07-21T18:56:07.653",
                      "last_delivery_status": 200,
                      "consecutive_failures": 0,
                      "events": [
                        "email.delivered",
                        "email.bounced"
                      ]
                    }
                  ],
                  "total": 1
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      },
      "post": {
        "summary": "Crea un webhook",
        "description": "Crea una nuova sottoscrizione webhook. La risposta contiene un `secret` che\nviene **mostrato una sola volta** — memorizzalo immediatamente, lato server. Usalo per\nverificare la firma HMAC di ogni payload in arrivo.\n\n**Limiti**: massimo 20 webhook per account, massimo 50 eventi 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": "Integrazione Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook creato — il `secret` viene restituito solo qui",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "email.delivered",
                    "email.bounced"
                  ],
                  "description": "Integrazione Slack",
                  "isActive": true,
                  "consecutiveFailures": 0,
                  "autoDisabledAt": null,
                  "autoDisabledReason": null,
                  "createdAt": "2026-05-25T10:00:00Z",
                  "updatedAt": "2026-05-25T10:00:00Z",
                  "secret": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
                }
              }
            }
          },
          "400": {
            "description": "URL non valido, elenco eventi non valido o limite superato"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servizio di gestione dei webhook"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "summary": "Ottieni un webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Il webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      },
      "put": {
        "summary": "Aggiorna un webhook",
        "description": "Aggiornamento parziale — solo i campi inviati vengono modificati.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook aggiornato",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "Payload non valido"
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      },
      "delete": {
        "summary": "Elimina un webhook",
        "description": "Elimina definitivamente il webhook e la sua intera cronologia di recapito.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Eliminato"
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servizio di gestione dei webhook"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Invia un evento di test",
        "description": "Mette in coda un evento `ping` immediato (o qualsiasi altro tipo di evento tramite il\ncampo body `eventType`) verso il tuo endpoint. Utile per verificare la raggiungibilità\ne la verifica della firma prima di affidarsi agli eventi reali.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventType": {
                    "type": "string",
                    "default": "ping"
                  }
                }
              },
              "example": {
                "eventType": "ping"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Evento messo in coda per il recapito",
            "content": {
              "application/json": {
                "example": {
                  "deliveryId": 1234,
                  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
                  "eventType": "ping"
                }
              }
            }
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servizio di gestione dei webhook"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Ruota il segreto HMAC",
        "description": "Genera un nuovo segreto HMAC e invalida immediatamente quello vecchio.\nIl nuovo segreto viene restituito **una sola volta** nella risposta — memorizzalo. Da questo\nmomento in poi ogni recapito verrà firmato con il nuovo segreto.\n\nUsalo se sospetti che il tuo segreto sia stato compromesso.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Nuovo segreto (visibile una sola volta)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
                }
              }
            }
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servizio di gestione dei webhook"
        }
      ],
      "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": "Cursore di paginazione (= ultimo ID di recapito visto). Restituisce i recapiti con `id < cursor`."
        }
      ],
      "get": {
        "summary": "Elenca i tentativi di recapito",
        "description": "Restituisce la cronologia dei tentativi di recapito per questo webhook (retention di 30 giorni).\nUtile per il debug — quali eventi sono stati inviati, i codici di stato ricevuti,\ni conteggi dei tentativi, i messaggi di errore.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array di tentativi di recapito (i più recenti per primi)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servizio di gestione dei webhook"
        }
      ],
      "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": "Riproduci un recapito",
        "description": "Mette in coda un nuovo tentativo di recapito con lo stesso payload dell'originale.\nUtile per ritentare un recapito fallito dopo aver corretto il tuo endpoint.\nViene creata una NUOVA riga `Webhook_Delivery` (l'originale viene preservata\nper l'audit). Il replay segue la policy di ritentativo standard\n(stessa schedulazione di backoff, stessa regola di disattivazione automatica dopo 10 fallimenti).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Replay messo in coda",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook o recapito non trovati"
          }
        }
      }
    }
  }
}