{
  "openapi": "3.0.3",
  "info": {
    "title": "API SMS Mailpro™",
    "version": "2",
    "description": "L'API SMS Mailpro™ consente di gestire in modo programmatico gli elenchi di contatti telefonici, i numeri di telefono e di inviare SMS in blocco o singoli.\n\n## Autenticazione\n\nOgni endpoint accetta **tre metodi di autenticazione**. Utilizza quello più adatto al tuo stack.\n\n- **OAuth 2.0** — token revocabili con ambito definito, per app di terze parti e piattaforme di integrazione (Zapier, Make, n8n). **I token OAuth sono soggetti a verifica di scope per endpoint** (vedi sotto).\n- **Bearer JWT** (legacy) — un token HMAC ottenuto da `POST /token`, senza scope.\n- **id_client + api_key** (legacy) — ID cliente + chiave API.\n\n> I metodi legacy Bearer JWT e id_client+api_key continuano a funzionare invariati e **non** sono soggetti a verifica di scope. Solo gli access token OAuth 2.0 sono sottoposti ai controlli di scope per endpoint mostrati in ciascuna operazione di seguito.\n\n### Metodo 1 — OAuth 2.0 (consigliato per le integrazioni)\n\nMailpro gestisce **un unico** authorization server OAuth 2.0 per tutte le sue API, su una superficie indipendente dalla versione: **`https://api.mailpro.com/oauth/`**. Non esiste un endpoint OAuth per versione: il token si ottiene da `/oauth/token` e lo **stesso** token funziona su questa API SMS, sull'API CRM v3 e sull'API Email v2. Quali endpoint può chiamare è determinato dagli **scope** del token, non dall'URL di base dell'API. Issuer (claim `iss`): `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Authorize | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / Refresh | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Discovery | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nGrant supportati: `authorization_code` **+ PKCE (S256, obbligatorio)**, `client_credentials`, `refresh_token` (con rotazione). TTL dell'access token: **20 min**; refresh token: **30 giorni** (sliding, monouso); auth code: **60 s**.\n\n**Quickstart — ottenere un token e chiamare questa API** (sostituisci i segnaposto; non committare mai un segreto reale):\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=sms:send sms:read\"\n```\n\nQuindi chiama questa API con `Authorization: Bearer ACCESS_TOKEN`. Lo stesso token funziona sulle API CRM v3 ed Email v2. Un token privo dello scope richiesto da un endpoint riceve **403 `insufficient_scope`**. Per la procedura completa del flusso e il catalogo degli scope, consulta la documentazione dell'API **CRM v3** › Autenticazione. Scope rilevanti per SMS: `sms:send`, `sms:read`, `sms:contacts:read`, `sms: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` (codifica form, grant OAuth2 password):\n\n```\nPOST https://api.mailpro.com/sms/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 sull'API CRM v3 e sull'API Email v2: ti autentichi una sola volta e puoi chiamare qualsiasi API. I token sono validi per **30 giorni** per impostazione predefinita; utilizza `grant_type=refresh_token` per rinnovarli senza dover ripetere l'autenticazione. Non hanno scope: preferisci OAuth 2.0 per le integrazioni installabili.\n\n### Metodo 3 — id_client + api_key\n\nDue credenziali:\n\n| Parametro   | Tipo    | Descrizione |\n|-------------|---------|-------------|\n| `id_client` | integer | Il tuo ID cliente Mailpro numerico, disponibile in **Impostazioni → Accesso API** |\n| `api_key`   | string  | La tua chiave API (formato GUID), disponibile in **Impostazioni → Accesso API** |\n\nInviale in uno di questi modi — scegline uno solo:\n\n1. **Header HTTP (consigliato)** — `id_client: 12345` e `api_key: a1b2c3d4-…`. Gli URL vengono registrati nei log di web server, CDN e proxy, quindi una chiave nella query string può finire nei log di accesso. Gli header non vengono registrati.\n2. **Query string (legacy, ancora funzionante)** — `?id_client=12345&api_key=…`. Mantenuto per compatibilità con le integrazioni esistenti. Passa agli header appena possibile.\n3. **Corpo JSON / form (solo POST)** — stessi nomi di campo all'interno del corpo della richiesta.\n\nSe fornisci le credenziali in più punti, **l'header ha la precedenza**.\n\n### Verifica degli scope OAuth per endpoint (SMS)\n\nPer i token emessi via OAuth, ogni gruppo di endpoint richiede uno scope (i metodi di autenticazione legacy ne sono esenti). Ogni operazione indica il proprio scope sotto **Authorization**. Riepilogo:\n\n| Endpoint | Scope richiesto |\n|-----------|----------------|\n| `/send/*` (invio in blocco, singolo, pianificazione) | `sms:send` |\n| `/history/list`, `/credit/get` | `sms:read` |\n| `/phone/list`, `/list/list` | `sms:contacts:read` |\n| `/phone/{add,edit,del}`, `/list/{edit,del}`, `/import/upload` | `sms:contacts:write` |\n| `/account/limits` | `account:read` |\n\n> `POST /list/add` (creazione di una lista) è attualmente raggiungibile da qualsiasi token valido — non è ancora sottoposto a verifica di scope. Il rifiuto per scope mancante sugli endpoint sottoposti a verifica restituisce **403** con `{ \"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- `/credit/get.json`\n- `/credit/get.xml`\n\nI nomi dei campi nelle risposte sono in **PascalCase** (`TotalCredits`, `FirstName`, …),\nmentre i parametri di richiesta sono in **snake_case** (`id_client`, `address_book_id`, …).\nGli endpoint di elenco racchiudono le loro righe in un array `Items`.\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\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## Costo in crediti di un SMS\n\nUn SMS costa **crediti del paese × numero di parti**.\n\n**Crediti del paese** — ogni paese di destinazione ha un prezzo di 1, 2 o 3\ncrediti, in base al prefisso internazionale del numero. L'invio a un numero il\ncui prefisso non è tariffato viene rifiutato con un `400`.\n\n**Numero di parti** — un messaggio più lungo di un SMS viene suddiviso\ndall'operatore e ogni parte viene addebitata. Il limite dipende dai caratteri\nutilizzati:\n\n| Alfabeto | Messaggio singolo | Per parte se suddiviso |\n|----------|-------------------|------------------------|\n| GSM-7 (latino standard) | 160 caratteri | 153 caratteri |\n| Unicode (accenti oltre GSM-7, cirillico, emoji, …) | 70 caratteri | 67 caratteri |\n\nUn **singolo** carattere fuori dal GSM-7 fa passare **tutto** il messaggio in\nUnicode; così un emoji può portare un messaggio di 160 caratteri da 1 a 3 parti.\nI caratteri `^ { } [ ] ~ | \\` e `€` contano **due** ciascuno, anche se sono\nGSM-7.\n\n*Esempio:* un messaggio di 300 caratteri in latino standard = 2 parti; inviato a\nun paese da 2 crediti, costa 2 × 2 = **4 crediti** per destinatario.\n\n## Formato dei numeri di telefono\n\nI numeri di telefono vengono normalizzati automaticamente. Puoi inviarli in molti formati: spazi, trattini, punti, barre, parentesi, underscore e spazi non separabili vengono rimossi prima della validazione. Qualsiasi altro carattere (lettere, apostrofi, `=`, `;`, ecc.) rende il numero non valido.\n\n| Valido                                         | Non valido                                         |\n|------------------------------------------------|----------------------------------------------------|\n| `+41794849980` — formato E.164 internazionale  | `0612345678` — formato nazionale (con `0` iniziale)|\n| `0041 79 484 99 80` — prefisso 00 + spazi      | `41'794'849'80` — apostrofi (non rimossi)          |\n| `+33 6-12-34-56-78` — + con trattini           | `tel=0041794849980` — caratteri extra               |\n| `41794849980` — solo cifre                     | `1234567` — troppo corto (< 8 cifre)                |\n\n**Regole:**\n- Prefissi accettati: `+`, `00` oppure nessun prefisso\n- Lunghezza dopo la normalizzazione: **da 8 a 15 cifre** (massimo E.164)\n- La prima cifra dopo la rimozione del prefisso deve essere **1–9** (non `0`)\n- Separatori rimossi: spazio, tabulazione, trattino `-`, punto `.`, barra `/`, parentesi `( )`, underscore `_`, NBSP\n- Qualsiasi altro carattere (lettere, apostrofi, `=`, `;`, `+` all'interno del numero, ecc.) → rifiutato\n- Forma memorizzata nel nostro database: solo cifre, senza prefisso (es. `41794849980`)\n\n## Codici di errore\n\n| HTTP | Codice | Significato |\n|------|--------|-------------|\n| 400  | 103    | Input malformato — parametro obbligatorio mancante o non valido |\n| 202  | 202    | Credito SMS insufficiente |\n| 401  |        | `id_client` / `api_key` non validi |\n| 500  | 500    | Errore interno |\n\n## Webhook\n\nMailpro™ può notificare il tuo server in tempo reale quando si verificano eventi SMS sul tuo account (un SMS viene consegnato, un SMS fallisce, il tuo saldo crediti è basso, ecc.). Stile Stripe: il tuo URL riceve una POST firmata HMAC-SHA256 non appena l'evento si verifica.\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 contiene un `secret` mostrato **una sola volta** (stile Stripe / GitHub): conservalo.\n2. **Mailpro invia in POST** un payload JSON firmato al tuo URL non appena un evento corrisponde.\n3. **Verifica la firma** lato server con il tuo `secret` (snippet di seguito).\n4. **Rispondi con 200–299** entro 10 secondi. In caso contrario verranno effettuati nuovi tentativi con backoff esponenziale (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, poi abbandono).\n\n> **⏱ Ritardo di attivazione** — dopo aver creato, aggiornato o eliminato un webhook, la modifica impiega fino a **10 minuti** per propagarsi su tutti i server API Mailpro. Durante tale finestra gli eventi potrebbero non corrispondere ancora alla tua nuova sottoscrizione (oppure potrebbero ancora corrispondere a una appena rimossa). È il tempo necessario per aggiornare la cache in memoria delle sottoscrizioni su ogni istanza API.\n\n### Envelope del payload\n\nTutti gli eventi condividono un envelope comune:\n\n```json\n{\n  \"id\":         \"evt_8f3a9b2c4d1e5f6789abcdef01234567\",\n  \"type\":       \"sms.queued\",\n  \"created\":    1748194800,\n  \"apiVersion\": \"sms\",\n  \"account\":    { \"id\": 12345, \"name\": \"ACME Corp\" },\n  \"data\":       {\n    \"messageId\":   12345,\n    \"to\":          \"41791234567\",\n    \"queuedAt\":    \"2026-05-27T14:32:12.0123456Z\",\n    \"scheduledAt\": \"2026-05-27T14:32:12.0123456Z\",\n    \"parts\":       1\n  }\n}\n```\n\n| Campo | Formato | Descrizione |\n|-------|---------|-------------|\n| `id` | `evt_` + 32 hex | ID univoco dell'evento — da usare come chiave di idempotenza dal tuo lato. |\n| `type` | `<dominio>.<verbo>` | Tipo di evento canonico. |\n| `created` | secondi Unix UTC | Incluso nella firma HMAC. |\n| `apiVersion` | `\"sms\"` per gli eventi emessi da `POST /sms/send/add_single`; `\"v3\"` per gli eventi emessi da `POST /v3/Sms/SingleSMS`; `\"watcher\"` per gli eventi guidati dalla DLR emessi dal worker. | Quale componente Mailpro ha pubblicato l'evento. |\n| `account.id` | int | Il tuo ID cliente Mailpro (= `id_client`). |\n| `account.name` | string | Il nome del tuo account (utile per il debug lato client). |\n| `data` | object | Payload dell'evento — la forma dipende da `type` (vedi catalogo di seguito). |\n\n### Catalogo degli eventi\n\nVengono effettivamente emessi solo gli eventi elencati di seguito. Le forme sono il JSON letterale inviato dalla piattaforma: rispetta esattamente questi nomi di campo durante il parsing.\n\n| Evento | Trigger | Forma di `data` |\n|--------|---------|-----------------|\n| `ping` | Test tramite `POST /webhooks/{id}/test` | `{ message }` |\n| `sms.queued` | `POST /sms/send/add_single` o `POST /v3/Sms/SingleSMS` accettato nella coda di invio Mailpro | `{ messageId: int, to: string, queuedAt: ISO-8601, scheduledAt: ISO-8601, parts: int }` |\n| `sms.delivered` | DLR con codice operatore `004` o `008` (codici di successo) | `{ messageId: int, phone: string, stateCode: string, dlrDate: datetime }` |\n| `sms.failed` | DLR con qualsiasi altro codice operatore (timeout, non consegnato, rifiutato, in blacklist, …) | `{ messageId: int, phone: string, stateCode: string, dlrDate: datetime }` |\n| `credits.sms.low` | Il saldo crediti SMS è sceso sotto la soglia di avviso (worker `CreditsLowWatcher`) | `{ remaining: int, threshold: int, alertedAt: ISO-8601 }` |\n\n> **Nota** — non esiste un evento `sms.sent`. La DLR dell'operatore è l'unico feedback che la piattaforma riceve tra \"queued\" e \"delivered/failed\", quindi l'evento successivo a `sms.queued` sarà `sms.delivered` (successo) oppure `sms.failed` (errore). La maggior parte dei messaggi raggiunge l'operatore in pochi secondi e ottiene una DLR in pochi minuti; le condizioni della rete mobile possono occasionalmente estendere questo intervallo a ore.\n\n> **Denominazione dei campi** — `sms.queued` usa `to` (la destinazione così come inviata dal chiamante dell'API, dopo normalizzazione). `sms.delivered` / `sms.failed` usano `phone` (la destinazione restituita dall'operatore nella DLR). In pratica le cifre saranno le stesse, ma i nomi differiscono perché gli eventi provengono da percorsi di codice diversi.\n\nSottoscriviti a 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: sms.delivered\nX-Mailpro-Attempt:   1\n```\n\nPer verificare:\n1. Estrai `t` e `v1` dall'header.\n2. **Rifiuta** la richiesta se `|now - t| > 300` (finestra di protezione anti-replay di 5 minuti).\n3. Calcola `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Confronta in tempo costante** `v1` con `expected` (`crypto.timingSafeEqual`, `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### Nuovi tentativi 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 (consegna contrassegnata come `failed`) |\n\nDopo **10 fallimenti consecutivi** sullo stesso webhook, questo viene **disattivato automaticamente** (`isActive: false`) e ricevi una email di notifica. Riattivalo con `PUT /webhooks/{id}` una volta corretto il tuo endpoint.\n\n### Successo = HTTP 2xx\n\nConsideriamo il tuo webhook come consegnato con successo solo se restituisci uno stato in `200–299`. Qualsiasi 3xx/4xx/5xx o un timeout (> 10 s) viene conteggiato come fallimento e attiva nuovi tentativi. Se il tuo endpoint è definitivamente fuori servizio, restituisci esplicitamente `410 Gone`: i tentativi continueranno comunque, ma il motivo del fallimento sarà più chiaro nel tuo log di consegna.\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 cronologia consegne | 30 giorni |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/sms",
      "description": "Produzione"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token JWT Bearer ottenuto da `POST /sms/token` (form-encoded, password\ngrant). Lo stesso token è valido anche sulle API CRM v3 ed\nEmail v2 — autenticati una volta, chiama 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": "id_client",
        "description": "Il tuo ID client numerico Mailpro — trasporto **preferito** (header HTTP).\nGli URL vengono registrati dai web server, da Cloudflare e dai proxy, quindi le\ncredenziali nella query string possono finire nei log di accesso. Gli header non vengono registrati.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "api_key",
        "description": "La tua API key (GUID) — trasporto **preferito** (header HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "id_client",
        "description": "Il tuo ID client numerico Mailpro — **legacy**, mantenuto per retrocompatibilità.\nPassa all'header `id_client` quando puoi.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "La tua API key (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": "header",
        "required": false,
        "description": "Elementi per pagina — 5.000 predefiniti e al massimo (vedi Paginazione). Header HTTP o parametro di query.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 5000
        },
        "example": 100
      },
      "pageNumber": {
        "name": "PageNumber",
        "in": "header",
        "required": false,
        "description": "Numero di pagina (a partire da 1) per le risposte paginate. Inviato come header HTTP.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      },
      "sortByName": {
        "name": "SortByName",
        "in": "header",
        "required": false,
        "description": "Imposta a `true` per ordinare i risultati alfabeticamente per nome.",
        "schema": {
          "type": "boolean",
          "default": false
        }
      }
    },
    "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 access token senza ri-autenticarsi"
          },
          "application": {
            "type": "string",
            "description": "Nome dell'integrazione (solo per i grant di terze parti)",
            "nullable": true
          }
        }
      },
      "PhoneList": {
        "type": "object",
        "properties": {
          "AddressBookId": {
            "type": "integer",
            "description": "Unique identifier of the phone list",
            "example": 42
          },
          "Name": {
            "type": "string",
            "description": "Nome visualizzato della lista telefonica",
            "example": "Newsletter subscribers"
          },
          "TotalNumberPhones": {
            "type": "integer",
            "description": "Number of phone numbers in this list",
            "example": 1547
          }
        }
      },
      "PhoneNumber": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificatore univoco della voce del numero di telefono",
            "example": 1001
          },
          "Number": {
            "type": "string",
            "description": "Numero di telefono in formato internazionale puro (forma memorizzata — vedi \"Formato del numero di telefono\" nella descrizione dell'API per i formati di input accettati)",
            "example": "41791234567"
          },
          "FirstName": {
            "type": "string",
            "description": "Nome del contatto",
            "example": "Alice"
          },
          "LastName": {
            "type": "string",
            "description": "Cognome del contatto",
            "example": "Dupont"
          }
        }
      },
      "SingleSend": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificatore univoco dell'invio creato",
            "example": 5001
          },
          "Message": {
            "type": "string",
            "description": "Il testo del messaggio SMS",
            "example": "Your verification code is 8472"
          },
          "ScheduledTime": {
            "type": "string",
            "format": "date-time",
            "description": "Quando l'SMS sarà (o è stato) inviato",
            "example": "2026-04-15T09:00:00"
          },
          "To": {
            "type": "string",
            "description": "Numero di telefono del destinatario",
            "example": "0041791234567"
          },
          "Charge": {
            "type": "string",
            "description": "Crediti effettivamente addebitati per questo invio = **crediti del paese × numero di parti**.\nEs. un SMS di 1 parte verso Panama (+507, 3 crediti/SMS) → `\"3\"`; un SMS di 2 parti → `\"6\"`.\n",
            "example": "3"
          },
          "Parts": {
            "type": "integer",
            "description": "Numero di segmenti SMS (parti GSM 03.38) in cui è stato suddiviso il messaggio.",
            "example": 1
          }
        }
      },
      "BulkSend": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificatore univoco dell'invio bulk creato",
            "example": 6001
          },
          "Message": {
            "type": "string",
            "description": "Il testo del messaggio SMS",
            "example": "Spring sale — 20% off all products this weekend!"
          },
          "ScheduledTime": {
            "type": "string",
            "format": "date-time",
            "description": "Quando la campagna SMS sarà (o è stata) inviata",
            "example": "2026-04-20T10:00:00"
          },
          "To": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Elenco degli ID delle liste destinatarie di questo invio",
            "example": [
              "42"
            ]
          },
          "Charge": {
            "type": "string",
            "description": "Crediti totali addebitati per l'intero invio = **Σ (crediti del paese × parti)**\nsu tutti i numeri della lista.\n",
            "example": "150"
          },
          "Parts": {
            "type": "integer",
            "description": "Numero di segmenti SMS (parti GSM 03.38) per messaggio.",
            "example": 1
          }
        }
      },
      "CreditBalance": {
        "type": "object",
        "properties": {
          "TotalCredits": {
            "type": "number",
            "description": "Saldo dei crediti SMS rimanente (crediti del piano + crediti mensili).\n\nÈ un conteggio di crediti, non un numero di messaggi: un SMS costa\n`crediti del paese × numero di parti` — vedi «Costo in crediti di un SMS» nella\ndescrizione dell'API.\n",
            "example": 5000
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "Error": {
            "type": "string",
            "description": "Messaggio di errore leggibile",
            "example": "Malformed Input"
          },
          "Code": {
            "type": "integer",
            "description": "Codice di errore specifico di Mailpro",
            "example": 103
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://example.com/hooks/mailpro"
          },
          "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
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipi di eventi sottoscritti. Un array vuoto indica ogni evento di questa API.",
            "example": [
              "sms.delivered",
              "sms.failed"
            ]
          }
        }
      },
      "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 a cui sottoscriversi (vedi catalogo sopra). Usa `[\"*\"]` per sottoscriverti a tutti gli eventi di questa API.",
            "example": [
              "sms.delivered",
              "sms.failed"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 500,
            "example": "Slack integration"
          }
        }
      },
      "WebhookCreateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "Segreto HMAC. **Mostrato qui una sola volta, mai più.** Conservalo lato server.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Aggiornamento parziale — ogni campo è opzionale.",
        "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 riabilitare un webhook disabilitato automaticamente una volta che il tuo endpoint è stato corretto."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "eventId": {
            "type": "string",
            "example": "evt_8f3a9b2c4d1e5f6789abcdef01234567"
          },
          "eventType": {
            "type": "string",
            "example": "sms.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\nSMS `/token` è un redirect 307 verso l'issuer canonico `/v3/token` —\nil tuo client HTTP segue il redirect in modo trasparente (il metodo POST e\nil body sono preservati).\n"
    },
    {
      "name": "Account",
      "description": "Controlla il saldo dei crediti SMS, la quota API mensile e lo stato dell'account."
    },
    {
      "name": "Send SMS",
      "description": "Invia messaggi SMS — un **singolo SMS transazionale** a un destinatario,\noppure una **campagna bulk** a un'intera lista di contatti.\n"
    },
    {
      "name": "Lists",
      "description": "Gestisci le liste di contatti SMS. Una lista di contatti raggruppa numeri di telefono per l'invio bulk.\nPuoi creare fino a 1.000 liste per account (stesso limite sulle tre API Mailpro e nell'app).\n"
    },
    {
      "name": "Phone Numbers",
      "description": "Gestisci i singoli numeri di telefono all'interno di una lista di contatti — aggiungi, aggiorna e rimuovi voci."
    },
    {
      "name": "Credit",
      "description": "Controlla il saldo residuo dei crediti SMS per il tuo account (separato dalla quota mensile di richieste API — vedi `/account/limits`)."
    },
    {
      "name": "History",
      "description": "Esplora il log completo delle campagne SMS passate."
    },
    {
      "name": "Import",
      "description": "Carica un file CSV o XLSX per importare numeri di telefono in una lista di contatti in modalità bulk.\nIl file viene accodato per l'elaborazione asincrona — traccia il completamento\ntramite l'`ImportJobId` restituito o tramite il callback opzionale `webhook_url`.\n"
    },
    {
      "name": "Webhooks",
      "description": "Sottoscrivi il tuo server alle notifiche di eventi SMS in tempo reale. Mailpro invia in POST\nun payload JSON firmato HMAC al tuo URL non appena l'evento sottoscritto\naccade. Consulta la sezione \"Webhook\" nell'introduzione per il catalogo completo\ndegli eventi, l'envelope del payload, gli snippet di verifica della firma e la policy di retry.\n"
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getSmsAccessToken",
        "summary": "Ottieni l'access token (redirect 307 verso /v3/token)",
        "security": [],
        "description": "Ottiene un token JWT Bearer usando le credenziali client Mailpro.\nPassa l'`access_token` restituito come `Authorization: Bearer <token>` in tutte\nle richieste successive. Lo stesso token è valido anche sulle API CRM v3 e\nEmail v2.\n\n> **⚙ Dettaglio implementativo** — `POST /sms/token` è un **307 Temporary\n> Redirect** verso `POST /v3/token` (configurato a livello di rewrite IIS in\n> `web.config`). HTTP 307 preserva sia il **metodo** (`POST`) sia il\n> **body della richiesta**, quindi qualsiasi client HTTP conforme agli standard segue\n> il redirect in modo trasparente — continui a fare POST verso `/sms/token` e ottieni\n> un JWT valido. Non c'è alcuna logica di emissione token duplicata; l'API\n> SMS non emette mai token in proprio.\n\n### Tipi di grant supportati\n| Tipo di grant | Caso d'uso |\n|------------|----------|\n| `password` | Integrazione standard — username + API key |\n| `refresh_token` | Rinnova un access token in scadenza senza ri-autenticarsi |\n| `client_credentials` | Server-to-server con solo il client ID |\n\n### Durata del token\n- Access token: **30 giorni**\n- Refresh token: **90 giorni**\n\nUsa `grant_type=refresh_token` per rinnovare l'access token senza\nri-autenticarti. Conserva i token lato server (Vault, variabili d'ambiente); non\nincorporarli mai nel JS del browser o nei binari delle app mobile. Consulta la nota\ndi sicurezza completa nella documentazione `/token` dell'API CRM v3.\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 API key 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\nseguimento trasparente del 307 — il tuo client HTTP vede un normale 200 con\nla stessa forma di 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": "Redirect temporaneo verso `POST /v3/token`, emesso dalla regola di rewrite\nIIS in `web.config`. I client HTTP conformi agli standard lo seguono\nautomaticamente e preservano il metodo POST originale + il body del form.\nVisibile solo ai client che disabilitano esplicitamente il seguimento dei redirect\n(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."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/credit/get.{format}": {
      "get": {
        "tags": [
          "Credit"
        ],
        "operationId": "getSmsCredits",
        "security": [
          {
            "OAuth2": [
              "sms:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Ottieni il saldo dei crediti SMS",
        "description": "Restituisce il saldo corrente dei crediti SMS per il tuo account.\nI crediti SMS vengono consumati al momento dell'invio. Un SMS standard (≤160 caratteri GSM-7)\ncosta 1 credito. I messaggi più lunghi o con caratteri speciali possono costare di più.\n\n> Nota: questo restituisce il tuo **saldo crediti di invio SMS**, non la tua quota di richieste API.\n> Per la quota API vedi `GET /account/limits.{format}`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo crediti restituito con successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalance"
                },
                "example": {
                  "TotalCredits": 5000
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSmsAccountLimits",
        "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 sui crediti dell'abbonamento\nemail (tipicamente `subscription_credits × 5`). Per un piano da 10.000 email/mese,\nquesto produce un budget mensile di 50.000 richieste. Reset alla **data di anniversario\ndell'abbonamento** (non il 1° del mese di calendario).\n\n**Cosa consuma crediti:**\n- Ogni richiesta API autenticata agli endpoint `v2`, `v3` o `sms`.\n- Ogni evento webhook inviato a un endpoint sottoscritto.\n\n**Cosa è GRATUITO (non consuma crediti):**\n- Endpoint `/health`.\n- Richieste che falliscono con `401`, `403` o `429`.\n- Eventi webhook per 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. Gli invii\nSMS consumano in aggiunta il saldo crediti SMS dedicato\n(`GET /credit/get.{format}`).\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": null
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "404": {
            "description": "Nessun record di quota trovato (account appena creato; la riga sarà creata alla prima richiesta autenticata)."
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listSmsHistory",
        "security": [
          {
            "OAuth2": [
              "sms:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca lo storico degli invii SMS",
        "description": "Restituisce un log paginato di tutte le campagne SMS passate inviate da questo account.\nI risultati sono ordinati per data decrescente (più recenti per primi).\nPaginazione: `NumberOfRecords` e `PageNumber` (header o query, 5.000 per pagina per impostazione predefinita).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista dello storico restituita con successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "Id": {
                            "type": "integer",
                            "description": "Identificatore dell'invio a cui appartiene questa riga",
                            "example": 583294
                          },
                          "DateSent": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Data e ora di consegna riportata dall'operatore",
                            "example": "2026-07-17T18:56:39.813"
                          },
                          "Message": {
                            "type": "string",
                            "example": "Your verification code is 8472"
                          },
                          "Charge": {
                            "type": "number",
                            "description": "Crediti addebitati per questa riga = **crediti del paese × numero di parti**\n(es. 3 per un SMS di 1 parte verso Panama). In precedenza sempre `1`.\n",
                            "example": 3
                          },
                          "Parts": {
                            "type": "integer",
                            "description": "Numero di segmenti SMS (parti GSM 03.38) in cui è stato suddiviso il messaggio.",
                            "example": 1
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "Items": [
                    {
                      "Id": 583294,
                      "DateSent": "2026-07-17T18:56:39.813",
                      "Message": "Your verification code is 8472",
                      "Charge": 3,
                      "Parts": 1
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listSmsLists",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca le liste di contatti telefonici",
        "description": "Restituisce tutte le liste di contatti SMS dell'account.\nUsa i valori `Id` restituiti per inviare campagne SMS bulk o aggiungere numeri di telefono.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Liste telefoniche restituite con successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PhoneList"
                      }
                    }
                  }
                },
                "example": {
                  "Items": [
                    {
                      "AddressBookId": 42,
                      "Name": "Newsletter subscribers",
                      "TotalNumberPhones": 1547
                    },
                    {
                      "AddressBookId": 43,
                      "Name": "Loyalty program",
                      "TotalNumberPhones": 823
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addSmsList",
        "summary": "Crea una lista di contatti",
        "description": "Crea una nuova lista di contatti SMS con il nome indicato.\nLa lista parte vuota — aggiungi i numeri di telefono con `POST /phone/add`.\nMassimo 1.000 liste per account (stesso limite sulle tre API Mailpro e nell'app). Restituisce HTTP 422 se il limite è raggiunto.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "name"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "name": {
                    "type": "string",
                    "description": "Nome visualizzato per la nuova lista di contatti",
                    "example": "Spring campaign 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista di contatti creata con successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneList"
                },
                "example": {
                  "Id": 44,
                  "Name": "Spring campaign 2026",
                  "NumberPhones": 0
                }
              }
            }
          },
          "400": {
            "description": "Campo obbligatorio mancante (name)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editSmsList",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rinomina una lista di contatti",
        "description": "Aggiorna il nome visualizzato di una lista di contatti SMS esistente.\nI numeri di telefono presenti nella lista non vengono modificati.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "address_book_id",
                  "name"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID della lista di contatti da rinominare (da `/list/list`)",
                    "example": 42
                  },
                  "name": {
                    "type": "string",
                    "description": "Nuovo nome visualizzato per la lista di contatti",
                    "example": "Spring campaign 2026 — updated"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista di contatti rinominata con successo"
          },
          "400": {
            "description": "Campo obbligatorio mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteSmsList",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elimina una lista di contatti",
        "description": "Elimina definitivamente una lista di contatti SMS **e tutti i numeri di telefono che contiene**.\nQuesta azione non può essere annullata.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "address_book_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID della lista di contatti da eliminare",
                    "example": 42
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista di contatti eliminata con successo"
          },
          "400": {
            "description": "address_book_id mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/phone/list.{format}": {
      "get": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "listPhones",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca i numeri di telefono in una lista di contatti",
        "description": "Restituisce un elenco paginato dei numeri di telefono in una specifica lista di contatti.\nUsa `address_book_id` per specificare quale lista recuperare.\nPaginazione: `NumberOfRecords` e `PageNumber` (5.000 per pagina per impostazione predefinita, pagina 1).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "address_book_id",
            "in": "query",
            "required": true,
            "description": "ID della lista di contatti da cui recuperare i numeri di telefono",
            "schema": {
              "type": "integer"
            },
            "example": 42
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "$ref": "#/components/parameters/sortByName"
          }
        ],
        "responses": {
          "200": {
            "description": "Numeri di telefono restituiti con successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PhoneNumber"
                      }
                    }
                  }
                },
                "example": {
                  "Items": [
                    {
                      "Id": 1001,
                      "Number": "41791234567",
                      "FirstName": "Alice",
                      "LastName": "Dupont"
                    },
                    {
                      "Id": 1002,
                      "Number": "33612345678",
                      "FirstName": "Bob",
                      "LastName": "Martin"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/phone/add.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "addPhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiungi numero/i di telefono a una lista",
        "description": "Aggiunge uno o più numeri di telefono a una lista di contatti.\n\n**Numero singolo:** usa il campo `number`.\n\n**Import bulk:** usa il campo `phone_list` con i numeri separati da punto e virgola:\n`+41791234567;+33612345678;0049301234567`\n\nI numeri di telefono accettano il formato `+`, `00` o quello puro — consulta **Formato del numero di telefono**\nnella descrizione dell'API per l'elenco completo degli input accettati / rifiutati.\nI numeri duplicati vengono saltati silenziosamente a meno che non sia impostato `force=1`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "address_book_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID della lista di contatti a cui aggiungere il/i numero/i",
                    "example": 42
                  },
                  "number": {
                    "type": "string",
                    "description": "Singolo numero di telefono. Accetta `+41…`, `0041…` o `41…` con o senza\nseparatori (spazi, trattini, punti, barre, parentesi). Consulta\n**Formato del numero di telefono** nella descrizione dell'API.\nUsa questo **OPPURE** `phone_list` — non entrambi.\n",
                    "example": "+41791234567"
                  },
                  "phone_list": {
                    "type": "string",
                    "description": "Elenco di numeri di telefono separati da punto e virgola per l'import bulk.\nUsa questo **OPPURE** `number` — non entrambi.\nEsempio: `0041791234567;0033612345678`\n",
                    "example": "0041791234567;0033612345678;0049301234567"
                  },
                  "firstname": {
                    "type": "string",
                    "description": "Nome del contatto (opzionale, solo per numero singolo)",
                    "example": "Alice"
                  },
                  "lastname": {
                    "type": "string",
                    "description": "Cognome del contatto (opzionale, solo per numero singolo)",
                    "example": "Dupont"
                  },
                  "force": {
                    "type": "integer",
                    "description": "Imposta a `1` per aggiungere un numero anche se in precedenza era stato disiscritto o esiste già.\nDefault: `0` (i duplicati vengono saltati).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Numero/i di telefono aggiunto/i con successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                },
                "example": {
                  "Id": 1003,
                  "Number": "0041791234567",
                  "FirstName": "Alice",
                  "LastName": "Dupont"
                }
              }
            }
          },
          "400": {
            "description": "Campo obbligatorio mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/phone/edit.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "editPhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aggiorna una voce di numero di telefono",
        "description": "Aggiorna il numero di telefono e/o i dettagli del contatto di una voce esistente.\nUsa `number_id` (da `/phone/list`) per identificare la voce da aggiornare.\nVengono aggiornati solo i campi forniti nella richiesta.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "number_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "number_id": {
                    "type": "integer",
                    "description": "ID della voce del numero di telefono da aggiornare (da `/phone/list`)",
                    "example": 1001
                  },
                  "number": {
                    "type": "string",
                    "description": "Nuovo numero di telefono. Accetta `+41…`, `0041…` o `41…` con o senza separatori. Consulta **Formato del numero di telefono** nella descrizione dell'API.",
                    "example": "+41791234568"
                  },
                  "firstname": {
                    "type": "string",
                    "description": "Nuovo nome per il contatto",
                    "example": "Alice"
                  },
                  "lastname": {
                    "type": "string",
                    "description": "Nuovo cognome per il contatto",
                    "example": "Dupont-Martin"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Voce del numero di telefono aggiornata con successo"
          },
          "400": {
            "description": "number_id mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/phone/del.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "deletePhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Rimuovi un numero di telefono da una lista",
        "description": "Rimuove definitivamente una specifica voce di numero di telefono dalla sua lista di contatti.\nUsa `number_id` (da `/phone/list`) per identificare la voce.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "number_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "number_id": {
                    "type": "integer",
                    "description": "ID della voce del numero di telefono da eliminare (da `/phone/list`)",
                    "example": 1001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Numero di telefono rimosso con successo"
          },
          "400": {
            "description": "number_id mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/add.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendBulkSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Invia SMS bulk a una lista di contatti",
        "description": "Invia un messaggio SMS a **tutti i numeri di telefono** in una lista di contatti.\nSupporta la pianificazione: imposta `scheduled_time` su una data futura per inviare in seguito,\noppure ometterlo per inviare immediatamente.\n\n**Consumo dei crediti:** i crediti vengono detratti al momento dell'invio.\nI messaggi lunghi (>160 caratteri GSM-7) vengono suddivisi in più parti,\nciascuna delle quali costa crediti aggiuntivi.\n\nLa risposta restituisce `{ \"Error\": \"Insufficient Credit\", \"Code\": 202 }` se\nl'account ha crediti insufficienti.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "message",
                  "to"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "message": {
                    "type": "string",
                    "description": "Testo del messaggio SMS. Mantienilo sotto i 160 caratteri per un SMS in singola parte.\nI caratteri al di fuori dell'alfabeto GSM-7 (es. cinese, arabo, emoji)\ncommutano la codifica in Unicode, riducendo il limite a 70 caratteri per parte.\n",
                    "example": "Flash sale today only — 30% off all orders. Shop now at mailpro.com/shop"
                  },
                  "to": {
                    "type": "integer",
                    "description": "ID della lista di contatti a cui inviare (da `/list/list`)",
                    "example": 42
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Pianifica l'invio per una data/ora futura (ISO 8601).\nOmetti o lascia vuoto per inviare immediatamente.\n",
                    "example": "2026-04-20T10:00:00"
                  },
                  "shorten_urls": {
                    "type": "boolean",
                    "default": false,
                    "description": "Imposta `true` per sostituire ogni link del messaggio con un link breve `https://mailp.ro/m/...`: meno caratteri, quindi a volte meno parti di SMS fatturate. Un link che non può essere abbreviato resta invariato."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invio SMS bulk creato con successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkSend"
                },
                "example": {
                  "Id": 6001,
                  "Message": "Flash sale today only — 30% off all orders. Shop now at mailpro.com/shop",
                  "ScheduledTime": "2026-04-20T10:00:00",
                  "To": [
                    "42"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Crediti SMS insufficienti",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Insufficient Credit",
                  "Code": 202
                }
              }
            }
          },
          "400": {
            "description": "Campo obbligatorio mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/add_single.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendSingleSmsGet",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Invia un singolo SMS (GET)",
        "description": "Invia un singolo SMS a un destinatario tramite una richiesta GET.\nUtile per integrazioni semplici dove POST non è disponibile.\nCredenziali e messaggio vengono passati come parametri della query string.\n\n**Nota:** evita di usare GET per messaggi sensibili — i parametri della query appaiono nei log del server.\nPreferisci invece `POST /send/add_single`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Numero di telefono del destinatario. Accetta `+41…`, `0041…` o `41…` con o senza separatori. Consulta **Formato del numero di telefono** nella descrizione dell'API.",
            "schema": {
              "type": "string"
            },
            "example": "+41791234567"
          },
          {
            "name": "message",
            "in": "query",
            "required": true,
            "description": "Testo del messaggio SMS (max 160 caratteri per la codifica standard)",
            "schema": {
              "type": "string"
            },
            "example": "Your appointment is confirmed for tomorrow at 10:00."
          },
          {
            "name": "scheduled_time",
            "in": "query",
            "description": "Pianifica l'invio (ISO 8601). Ometti per inviare immediatamente.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "shorten_urls",
            "in": "query",
            "description": "Imposta `true` per sostituire ogni link del messaggio con un link breve `https://mailp.ro/m/...`: meno caratteri, quindi a volte meno parti di SMS fatturate. Un link che non può essere abbreviato resta invariato.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SMS inviato (o pianificato) con successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SingleSend"
                },
                "example": {
                  "Id": 5001,
                  "Message": "Your appointment is confirmed for tomorrow at 10:00.",
                  "ScheduledTime": "2026-04-15T09:00:00",
                  "To": "0041791234567",
                  "Charge": "1"
                }
              }
            }
          },
          "202": {
            "description": "Crediti SMS insufficienti",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "400": {
            "description": "Parametro obbligatorio mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      },
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendSingleSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Invia un singolo SMS",
        "description": "Invia un singolo messaggio SMS a un numero di telefono destinatario.\nSupporta la pianificazione tramite `scheduled_time`.\n\n**Consumo dei crediti:** i crediti vengono detratti al momento dell'invio.\nIl campo `Charge` nella risposta indica quanti crediti sono stati consumati.\n\nLa risposta restituisce `{ \"Error\": \"Insufficient Credit\", \"Code\": 202 }` se\nl'account ha crediti insufficienti.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "message",
                  "to"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "message": {
                    "type": "string",
                    "description": "Testo del messaggio SMS",
                    "example": "Your verification code is 8472. Valid for 10 minutes."
                  },
                  "to": {
                    "type": "string",
                    "description": "Numero di telefono del destinatario. Accetta `+41…`, `0041…` o `41…` con o senza separatori. Consulta **Formato del numero di telefono** nella descrizione dell'API.",
                    "example": "+41791234567"
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Pianifica l'invio per un'ora futura. Ometti per inviare immediatamente.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "shorten_urls": {
                    "type": "boolean",
                    "default": false,
                    "description": "Imposta `true` per sostituire ogni link del messaggio con un link breve `https://mailp.ro/m/...`: meno caratteri, quindi a volte meno parti di SMS fatturate. Un link che non può essere abbreviato resta invariato."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS inviato (o pianificato) con successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SingleSend"
                },
                "example": {
                  "Id": 5001,
                  "Message": "Your verification code is 8472. Valid for 10 minutes.",
                  "ScheduledTime": "2026-04-15T14:30:00",
                  "To": "0041791234567",
                  "Charge": "1"
                }
              }
            }
          },
          "202": {
            "description": "Crediti SMS insufficienti",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Insufficient Credit",
                  "Code": 202
                }
              }
            }
          },
          "400": {
            "description": "Campo obbligatorio mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "listSmsSends",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca le campagne SMS",
        "description": "Restituisce l'elenco delle campagne SMS (invii bulk) dell'account.\nPaginazione tramite gli header `NumberOfRecords` e `PageNumber`.\n\nUsa `type_to` per filtrare per tipo di invio:\n- `0` (default) — invii bulk verso una lista\n- `1` — invii individuali singoli\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type_to",
            "in": "query",
            "description": "Filtro per tipo di invio:\n- `0` (default) — invii bulk verso una lista di contatti\n- `1` — invii individuali a singolo numero\n",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco delle campagne SMS restituito con successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SingleSend"
                  }
                },
                "example": [
                  {
                    "Id": 5001,
                    "Message": "Your verification code is 8472",
                    "ScheduledTime": "2026-04-15T09:00:00",
                    "To": "41791234567"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "deleteSmsSend",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annulla o elimina un invio SMS",
        "description": "Annulla un invio SMS **in attesa pianificato**, oppure elimina un invio **completato** dallo storico.\nSolo gli invii pianificati nel 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": [
                  "id_client",
                  "api_key",
                  "id_send"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Il tuo ID client Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "La tua API key (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "id_send": {
                    "type": "integer",
                    "description": "ID dell'invio SMS da annullare o eliminare (da `/send/list`)",
                    "example": 6001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invio SMS annullato o eliminato con successo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "id_send mancante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "500": {
            "description": "Eliminazione fallita (invio non trovato o già processato)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Delete failed",
                  "Code": 500
                }
              }
            }
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "listScheduledSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Elenca i miei invii SMS pianificati",
        "description": "Restituisce gli invii SMS (singoli o campagne) pianificati per una data futura che\nnon sono ancora stati spediti. Utile prima di chiamare `/cancel` o `/reschedule`.\n\nI record sono ordinati per `scheduled_time` crescente.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "id_client",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 12345
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco degli invii SMS pianificati",
            "content": {
              "application/json": {
                "example": [
                  {
                    "Id": 9001,
                    "Message": "Black Friday: 30% off until midnight.",
                    "ScheduledTime": "2026-11-27T12:00:00",
                    "To": "+33671234567"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/send/{id_send}/cancel.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "cancelScheduledSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Annulla un invio SMS pianificato",
        "description": "Annulla un SMS pianificato che non è ancora stato spedito. Se l'invio è\ngià stato processato (o non esiste / appartiene a un altro client),\nrestituisce **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "id_send",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 9001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "example": "a1b2c3d4-..."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invio annullato",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 9001
                }
              }
            }
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "409": {
            "description": "Già spedito o non trovato",
            "content": {
              "application/json": {
                "example": {
                  "error": "conflict",
                  "message": "Send not found, not owned by client, or already dispatched."
                }
              }
            }
          }
        }
      }
    },
    "/send/{id_send}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "rescheduleSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Riprogramma un invio SMS pianificato",
        "description": "Aggiorna la data pianificata di un SMS programmato che non è ancora stato spedito.\nLa nuova data deve essere **nel futuro** e **entro 90 giorni**.\n\n**Nome del campo data:** l'API accetta `scheduled_time` (primario) così come\ngli alias legacy `PlanDate`, `date_planned` e `DatePlanned`. Fornisci\nuno qualsiasi di essi — viene usato il primo non null.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "id_send",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 9001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key"
                ],
                "description": "Fornisci uno tra `scheduled_time`, `PlanDate`, `date_planned` o `DatePlanned`.",
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "example": "a1b2c3d4-..."
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Nome del campo primario.",
                    "example": "2026-12-31T14:30:00"
                  },
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias legacy accettato per retrocompatibilità."
                  },
                  "date_planned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias legacy accettato per retrocompatibilità."
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias legacy accettato per retrocompatibilità."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invio riprogrammato",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 9001,
                  "NewScheduledTime": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "scheduled_time mancante o non valido"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "409": {
            "description": "Già spedito, non trovato o nuova data fuori intervallo",
            "content": {
              "application/json": {
                "example": {
                  "error": "conflict",
                  "message": "Reschedule failed — send not found, already dispatched, or new date out of range."
                }
              }
            }
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Carica un file di numeri di telefono (CSV / XLSX) per l'import bulk",
        "description": "Carica un file CSV o XLSX per importare numeri di telefono in una lista di contatti.\nIl file viene memorizzato e accodato 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- `id_client` (intero) — il tuo ID client Mailpro\n- `api_key` (stringa) — la tua API key\n- `id_list` (intero) — ID della lista di contatti di destinazione\n- `file` (binario) — il file CSV o XLSX da caricare\n\n**Opzionale:**\n- `webhook_url` (stringa) — URL HTTPS chiamato al termine dell'elaborazione.\n  Riceve un payload JSON con lo stato finale (success / failed) e\n  i conteggi delle righe importate / saltate / non valide.\n\n**Formato del file:**\n- Codifica UTF-8\n- Prima riga = intestazioni (una deve essere `Phone` o `PhoneNumber` — case-insensitive)\n- Numeri in formato internazionale (E.164), es. `+41791234567`\n- Dimensione massima del file: 50 MB\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "id_list",
                  "file"
                ],
                "properties": {
                  "id_list": {
                    "type": "integer",
                    "format": "int64",
                    "description": "ID della lista di contatti di destinazione",
                    "example": 11088
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "File CSV o XLSX (UTF-8, max 50 MB)"
                  },
                  "webhook_url": {
                    "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 accodato",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 15,
                  "InternalName": "230575-20260420142616-phones.csv"
                }
              }
            }
          },
          "400": {
            "description": "Nessun file caricato o id_list mancante"
          },
          "401": {
            "description": "Credenziali non valide"
          },
          "500": {
            "description": "Errore del server o dello storage"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Servizio di gestione dei webhook (separato dall'host API principale)"
        }
      ],
      "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": [
                        "sms.delivered",
                        "sms.failed"
                      ]
                    }
                  ],
                  "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** — conservalo 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": [
                  "sms.delivered",
                  "sms.failed"
                ],
                "description": "Integrazione Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook creato — `secret` restituito solo qui",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "sms.delivered",
                    "sms.failed"
                  ],
                  "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, elenco eventi non valido o limite superato"
          },
          "401": {
            "description": "Credenziali non valide"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "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 — vengono modificati solo i campi inviati.",
        "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 tutto il suo storico di consegne.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Eliminato"
          },
          "404": {
            "description": "Webhook non trovato"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "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": "Accoda un evento `ping` immediato (o qualsiasi altro tipo di evento tramite il campo\n`eventType` nel body) verso il tuo endpoint. Utile per verificare la raggiungibilità\ne la verifica della firma prima di basarsi su 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 accodato per la spedizione",
            "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/sms",
          "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 — conservalo. Ogni\nconsegna da questo momento in poi sarà firmata 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/sms",
          "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 consegna visto). Restituisce le consegne con `id < cursor`."
        }
      ],
      "get": {
        "summary": "Elenca i tentativi di consegna",
        "description": "Restituisce lo storico dei tentativi di spedizione per questo webhook (retention di 30 giorni).\nUtile per il debug — quali eventi sono stati inviati, codici di stato ricevuti,\nconteggi dei retry, messaggi di errore.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array di tentativi di consegna (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/sms",
          "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 una consegna",
        "description": "Accoda un nuovo tentativo di consegna con lo stesso payload dell'originale.\nUtile per ri-scatenare una consegna fallita dopo aver corretto il tuo endpoint.\nViene creata una NUOVA riga `Webhook_Delivery` (l'originale viene preservata\nper audit). La riproduzione segue la policy di retry standard\n(stesso schedule di backoff, stessa regola di auto-disabilitazione a 10 fallimenti).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Riproduzione accodata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook o consegna non trovati"
          }
        }
      }
    }
  }
}