{
  "openapi": "3.0.3",
  "info": {
    "title": "API SMS Mailpro™",
    "version": "2",
    "description": "A API SMS Mailpro™ permite gerir programaticamente listas de contactos telefónicos,\nnúmeros de telefone e enviar SMS em massa ou individualmente.\n\n## Autenticação\n\nTodos os endpoints aceitam **três métodos de autenticação**. Utilize aquele que melhor\nse adeque à sua stack.\n\n- **OAuth 2.0** — tokens com scopes e revogáveis, para aplicações de terceiros e\n  plataformas de integração (Zapier, Make, n8n). **Os tokens OAuth são restringidos por scope\n  em cada endpoint** (ver abaixo).\n- **Bearer JWT** (legado) — um token HMAC obtido em `POST /token`, sem scopes.\n- **id_client + api_key** (legado) — ID de cliente + chave de API.\n\n> O Bearer JWT legado e o id_client+api_key continuam a funcionar sem alterações e **não**\n> são restringidos por scope. Apenas os tokens de acesso OAuth 2.0 estão sujeitos às\n> verificações de scope por endpoint apresentadas em cada operação abaixo.\n\n### Método 1 — OAuth 2.0 (recomendado para integrações)\n\nA Mailpro disponibiliza **um único** servidor de autorização OAuth 2.0 para todas as suas APIs,\nnuma superfície única e independente da versão: **`https://api.mailpro.com/oauth/`**. Não existe\num endpoint OAuth por versão — obtém um token em `/oauth/token` e o **mesmo** token\nfunciona nesta API SMS, na CRM v3 e na Email v2. Os endpoints que poderá invocar\nsão determinados pelos **scopes** do token e não pelo URL base da API. Emissor (claim `iss`):\n`https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Authorize | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / Refresh | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Discovery | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nGrants: `authorization_code` **+ PKCE (S256, obrigatório)**, `client_credentials`,\n`refresh_token` (rotação). TTL do token de acesso **20 min**; refresh token **30 dias**\n(deslizante, de uso único); código de autorização **60 s**.\n\n**Quickstart — obter um token e invocar esta API** (substitua os marcadores; nunca\nfaça commit de um secret real):\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\nDepois invoque esta API com `Authorization: Bearer ACCESS_TOKEN`. O mesmo token\nfunciona nas APIs CRM v3 e Email v2. Um token sem o scope exigido por um endpoint\nrecebe **403 `insufficient_scope`**. Para o passo a passo completo do fluxo e o\ncatálogo de scopes, consulte a documentação da API **CRM v3** › Autenticação. Scopes\nrelevantes para SMS: `sms:send`, `sms:read`, `sms:contacts:read`, `sms:contacts:write`,\n`account:read`.\n\n### Método 2 — Bearer JWT (legado)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nObtenha um token via `POST /token` (form-encoded, OAuth2 password grant):\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\nO mesmo token também é válido na API CRM v3 e na API Email v2 —\nautentique-se uma vez e invoque qualquer API. Os tokens são válidos por **30 dias** por defeito;\nutilize `grant_type=refresh_token` para os renovar sem voltar a autenticar. Não tem scopes\n— prefira o OAuth 2.0 para integrações instaláveis.\n\n### Método 3 — id_client + api_key\n\nDuas credenciais:\n\n| Parâmetro   | Tipo    | Descrição |\n|-------------|---------|-------------|\n| `id_client` | integer | O seu ID numérico de cliente Mailpro, disponível em **Definições → Acesso à API** |\n| `api_key`   | string  | A sua chave de API (formato GUID), disponível em **Definições → Acesso à API** |\n\nEnvie-as num destes locais — escolha um:\n\n1. **Cabeçalhos HTTP (recomendado)** — `id_client: 12345` e `api_key: a1b2c3d4-…`.\n   Os URLs são registados por servidores web, CDNs e proxies, pelo que uma chave na query string\n   pode acabar exposta nos logs de acesso. Os cabeçalhos não são registados.\n2. **Query string (legado, ainda funciona)** — `?id_client=12345&api_key=…`.\n   Mantido por retrocompatibilidade com integrações existentes. Mude para\n   cabeçalhos assim que possível.\n3. **Corpo JSON / form (apenas POST)** — os mesmos nomes de campos dentro do corpo do pedido.\n\nSe fornecer credenciais em mais do que um local, **o cabeçalho prevalece**.\n\n### Aplicação de scopes OAuth por endpoint (SMS)\n\nPara tokens emitidos via OAuth, cada grupo de endpoints exige um scope (a autenticação legada está\nisenta). Cada operação indica o seu scope em **Authorization**. Resumo:\n\n| Endpoints | Scope exigido |\n|-----------|----------------|\n| `/send/*` (em massa, individual, agendamento) | `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> O `POST /list/add` (criar uma lista) é atualmente acessível por qualquer\n> token válido — ainda não é restringido por scope. A rejeição por scope nos endpoints\n> restringidos devolve **403** com\n> `{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }`.\n\n## Formato da resposta\n\nTodos os endpoints suportam `json` (predefinição) e `xml`. Especifique o formato no URL:\n- `/credit/get.json`\n- `/credit/get.xml`\n\nOs nomes dos campos nas respostas estão em **PascalCase** (`TotalCredits`, `FirstName`, …),\nenquanto os parâmetros de pedido estão em **snake_case** (`id_client`, `address_book_id`, …).\nOs endpoints de lista envolvem as suas linhas num array `Items`.\n\n## Paginação\n\n**Mesma regra nas três API Mailpro** (Email v2, CRM v3, SMS): **5000 itens por página,\npor predefinição e no máximo.**\n- `NumberOfRecords` — itens por página. Ausente, `0` ou acima de 5000 = 5000.\n- `PageNumber` — número de página a partir de 1 (predefinição 1).\n- Ambos são aceites como parâmetro de query **ou** como cabeçalho HTTP.\n- Uma página cheia significa que pode haver mais: peça a página seguinte até receber\n  uma página incompleta.\n\n**Parâmetros desconhecidos**: são ignorados, nunca recusados. Quando um pedido contém um parâmetro que a API\nnão reconhece, a resposta inclui `X-Ignored-Parameters` (os nomes) e `X-Documentation` (uma ligação para\nesta página), para que um erro de escrita não passe despercebido.\n\n## Custo em créditos de um SMS\n\nUm SMS custa **créditos do país × número de partes**.\n\n**Créditos do país** — cada país de destino tem um preço de 1, 2 ou 3 créditos,\ncom base no prefixo internacional do número. O envio para um número cujo prefixo\nnão tarifamos é rejeitado com um `400`.\n\n**Número de partes** — uma mensagem mais longa do que um SMS é dividida pelo\noperador e cada parte é cobrada. O limite depende dos caracteres utilizados:\n\n| Alfabeto | Mensagem única | Por parte quando dividida |\n|----------|----------------|----------------------------|\n| GSM-7 (latino padrão) | 160 caracteres | 153 caracteres |\n| Unicode (acentos fora do GSM-7, cirílico, emoji, …) | 70 caracteres | 67 caracteres |\n\nUm **único** carácter fora do GSM-7 passa **toda** a mensagem para Unicode;\nassim, um emoji pode levar uma mensagem de 160 caracteres de 1 para 3 partes.\nOs caracteres `^ { } [ ] ~ | \\` e `€` contam como **dois** cada um, embora\nsejam GSM-7.\n\n*Exemplo:* uma mensagem de 300 caracteres em latino padrão = 2 partes; enviada\npara um país de 2 créditos, custa 2 × 2 = **4 créditos** por destinatário.\n\n## Formato do número de telefone\n\nOs números de telefone são normalizados automaticamente. Pode enviá-los em vários formatos —\nespaços, hífenes, pontos, barras, parênteses, underscores e espaços não separáveis\nsão removidos antes da validação. Qualquer outro carácter (letras, apóstrofos,\n`=`, `;`, etc.) torna o número inválido.\n\n| Válido                                          | Inválido                                            |\n|------------------------------------------------|----------------------------------------------------|\n| `+41794849980` — E.164 internacional           | `0612345678` — formato nacional (`0` inicial)       |\n| `0041 79 484 99 80` — prefixo 00 + espaços     | `41'794'849'80` — apóstrofos (não removidos)       |\n| `+33 6-12-34-56-78` — + com hífenes            | `tel=0041794849980` — caracteres adicionais        |\n| `41794849980` — apenas dígitos                 | `1234567` — demasiado curto (< 8 dígitos)          |\n\n**Regras:**\n- Prefixos aceites: `+`, `00` ou sem prefixo\n- Comprimento após normalização: **8 a 15 dígitos** (máximo E.164)\n- O primeiro dígito após a remoção do prefixo deve ser **1–9** (não `0`)\n- Separadores removidos: espaço, tabulação, hífen `-`, ponto `.`, barra `/`, parênteses `( )`, underscore `_`, NBSP\n- Qualquer outra coisa (letras, apóstrofos, `=`, `;`, `+` dentro do número, etc.) → rejeitado\n- Forma armazenada na nossa base de dados: apenas dígitos, sem prefixo (por exemplo `41794849980`)\n\n## Códigos de erro\n\n| HTTP | Código | Significado |\n|------|------|---------|\n| 400  | 103  | Entrada malformada — parâmetro obrigatório em falta ou inválido |\n| 202  | 202  | Créditos SMS insuficientes |\n| 401  |      | `id_client` / `api_key` inválidos |\n| 500  | 500  | Erro interno |\n\n## Webhooks\n\nA Mailpro™ pode notificar o seu servidor em tempo real quando ocorrem eventos SMS na sua\nconta (um SMS é entregue, um SMS falha, o seu saldo de créditos está baixo, etc.).\nAo estilo Stripe — o seu URL recebe um POST assinado com HMAC-SHA256 assim que o\nevento dispara.\n\nCada evento enviado para o seu webhook conta como 1 pedido na sua quota de pedidos à API.\n\n### Como funciona\n\n1. **Subscreva** um ou mais tipos de evento via `POST /webhooks`. A resposta\n   contém um `secret` mostrado **uma única vez** (estilo Stripe / GitHub) — guarde-o.\n2. **A Mailpro envia um POST** com um payload JSON assinado para o seu URL assim que um evento corresponder.\n3. **Verifique a assinatura** no lado do servidor com o seu `secret` (snippets abaixo).\n4. **Responda 200–299** em 10 segundos. Caso contrário, tentamos novamente com backoff exponencial\n   (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, depois desistimos).\n\n> **⏱ Atraso de ativação** — depois de criar, atualizar ou eliminar um webhook, a\n> alteração demora até **10 minutos** a propagar-se pelos servidores da API Mailpro.\n> Durante essa janela, os eventos podem ainda não corresponder à sua nova subscrição\n> (ou continuar a corresponder a uma acabada de remover). Este é o tempo necessário para\n> atualizar a cache em memória de subscrições em cada instância da API.\n\n### Envelope do payload\n\nTodos os eventos partilham um envelope comum:\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 | Descrição |\n|-------|--------|-------------|\n| `id` | `evt_` + 32 hex | ID único do evento — utilize-o como chave de idempotência do seu lado. |\n| `type` | `<domínio>.<verbo>` | Tipo canónico do evento. |\n| `created` | Segundos Unix UTC | Incluído na assinatura HMAC. |\n| `apiVersion` | `\"sms\"` para eventos emitidos por `POST /sms/send/add_single`; `\"v3\"` para eventos emitidos por `POST /v3/Sms/SingleSMS`; `\"watcher\"` para eventos baseados em DLR emitidos pelo worker. | Qual o componente Mailpro que publicou o evento. |\n| `account.id` | int | O seu ID de cliente Mailpro (= `id_client`). |\n| `account.name` | string | O nome da sua conta (útil para debug do lado do cliente). |\n| `data` | object | Payload do evento — a estrutura depende do `type` (ver catálogo abaixo). |\n\n### Catálogo de eventos\n\nApenas os eventos listados abaixo são efetivamente emitidos. As estruturas correspondem ao JSON\nliteral enviado pela plataforma — utilize exatamente estes nomes de campos ao fazer parsing.\n\n| Evento | Disparo | Estrutura de `data` |\n|-------|---------|--------------|\n| `ping` | Teste via `POST /webhooks/{id}/test` | `{ message }` |\n| `sms.queued` | `POST /sms/send/add_single` ou `POST /v3/Sms/SingleSMS` aceite na fila de envio Mailpro | `{ messageId: int, to: string, queuedAt: ISO-8601, scheduledAt: ISO-8601, parts: int }` |\n| `sms.delivered` | DLR com código de operadora `004` ou `008` (códigos de sucesso) | `{ messageId: int, phone: string, stateCode: string, dlrDate: datetime }` |\n| `sms.failed` | DLR com qualquer outro código de operadora (timeout, não entregue, rejeitado, em lista negra, …) | `{ messageId: int, phone: string, stateCode: string, dlrDate: datetime }` |\n| `credits.sms.low` | Saldo de créditos SMS desceu abaixo do seu limiar de alerta (worker `CreditsLowWatcher`) | `{ remaining: int, threshold: int, alertedAt: ISO-8601 }` |\n\n> **Nota** — não existe um evento `sms.sent`. O DLR da operadora é o único feedback\n> que a plataforma recebe entre \"queued\" e \"delivered/failed\", pelo que o próximo\n> evento que receberá após `sms.queued` será `sms.delivered` (sucesso) ou\n> `sms.failed` (erro). A maioria das mensagens chega à operadora em segundos e o\n> DLR em minutos; as condições da rede móvel podem ocasionalmente prolongar este prazo\n> para horas.\n\n> **Nomenclatura dos campos** — `sms.queued` utiliza `to` (o destino tal como submetido\n> pelo invocador da API, após normalização). `sms.delivered` / `sms.failed` utilizam\n> `phone` (o destino tal como devolvido pela operadora no DLR). Na prática serão\n> os mesmos dígitos, mas os nomes diferem porque os eventos\n> têm origem em caminhos de código distintos.\n\nSubscreva todos os eventos desta API passando `[\"*\"]` no array `events`.\n\n### Assinatura HMAC\n\nCada POST inclui um cabeçalho `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\nPara verificar:\n1. Extraia `t` e `v1` do cabeçalho.\n2. **Rejeite** se `|now - t| > 300` (janela de proteção contra replay de 5 minutos).\n3. Calcule `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Compare em tempo constante** `v1` com `expected` (`crypto.timingSafeEqual`,\n   `hash_equals`, `CryptographicOperations.FixedTimeEquals`) — nunca `==`.\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### Tentativas e desativação automática\n\n| Tentativa | Atraso até à próxima tentativa |\n|---------|----------------------|\n| 1 → 2 | 10 segundos |\n| 2 → 3 | 1 minuto |\n| 3 → 4 | 5 minutos |\n| 4 → 5 | 30 minutos |\n| 5 → 6 | 2 horas |\n| 6 → 7 | 6 horas |\n| 7 | abandonada (entrega marcada como `failed`) |\n\nApós **10 falhas consecutivas** no mesmo webhook, este é **automaticamente\ndesativado** (`isActive: false`) e receberá uma notificação por email. Reative-o\ncom `PUT /webhooks/{id}` assim que o seu endpoint estiver corrigido.\n\n### Sucesso = HTTP 2xx\n\nConsideramos o seu webhook como bem-sucedido apenas se devolver um status entre `200–299`.\nQualquer 3xx/4xx/5xx ou um timeout (> 10 s) conta como falha e desencadeia novas tentativas.\nSe o seu endpoint estiver permanentemente inativo, devolva explicitamente `410 Gone` — as tentativas\ncontinuam a ocorrer, mas o motivo da falha fica mais claro no seu log de entregas.\n\n### Limites\n\n| Limite | Valor |\n|-------|-------|\n| Webhooks por conta | 20 |\n| Eventos subscritos por webhook | 50 |\n| Tamanho máximo do payload | 256 KB |\n| Timeout HTTP por tentativa | 10 segundos |\n| Retenção do histórico de entregas | 30 dias |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/sms",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token JWT Bearer obtido através de `POST /sms/token` (form-encoded, password\ngrant). O mesmo token é igualmente válido na API CRM v3 e na\nAPI Email v2 — autentique-se uma vez, invoque qualquer API.\nEnvie-o como: `Authorization: Bearer <token>`\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Mailpro OAuth 2.0 — a forma moderna para aplicações de terceiros e plataformas\nde integração (Zapier, Make, n8n) actuarem em nome de um utilizador Mailpro com\ntokens de acesso revogáveis e delimitados por âmbito.\n\n- **authorizationCode + PKCE** (S256, obrigatório para clientes públicos) — o\n  fluxo de consentimento \"Connect Mailpro\". Emite um token de acesso + um\n  refresh token rotativo.\n- **clientCredentials** — máquina-a-máquina, sem utilizador envolvido.\n\nUm servidor de autorização para todas as APIs, na superfície independente de versão\n`https://api.mailpro.com/oauth/` (emissor / claim `iss`\n`https://api.mailpro.com/oauth/`). Os tokens de acesso são JWTs RS256\n(verifique através do JWKS em `https://api.mailpro.com/oauth/.well-known/jwks`);\nTTL **20 minutos**. Os refresh tokens são válidos durante **30 dias** (deslizante) e\nsão de **utilização única** (rotacionados a cada renovação). Os códigos de autorização\nvivem **60 segundos**.\n\nO mesmo token de acesso OAuth é aceite pelas três APIs Mailpro\n(CRM v3, Email v2, SMS) — autentique-se uma vez, invoque qualquer API; o acesso é\nregido pelos âmbitos do token, não pelo URL base da API. A autenticação legada\n(Bearer JWT / IdClient+ApiKey) continua a funcionar inalterada e NÃO\nestá sujeita a controlo por âmbito.\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": "O seu ID de cliente Mailpro numérico — transporte **preferido** (cabeçalho HTTP).\nOs URLs são registados pelos servidores web, pelo Cloudflare e pelos proxies, pelo que\ncredenciais em query-string podem vazar para os registos de acesso. Os cabeçalhos não são registados.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "api_key",
        "description": "A sua chave de API (GUID) — transporte **preferido** (cabeçalho HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "id_client",
        "description": "O seu ID de cliente Mailpro numérico — **legado**, mantido por compatibilidade retroactiva.\nMude para o cabeçalho `id_client` assim que possível.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "A sua chave de API (GUID) — **legado**, mantido por compatibilidade retroactiva.\n"
      }
    },
    "parameters": {
      "format": {
        "name": "format",
        "in": "path",
        "required": true,
        "description": "Formato da resposta",
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "xml"
          ],
          "default": "json"
        },
        "example": "json"
      },
      "numberOfRecords": {
        "name": "NumberOfRecords",
        "in": "header",
        "required": false,
        "description": "Itens por página — 5000 por predefinição e no máximo (ver Paginação). Cabeçalho HTTP ou parâmetro de query.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 5000
        },
        "example": 100
      },
      "pageNumber": {
        "name": "PageNumber",
        "in": "header",
        "required": false,
        "description": "Número de página com base 1 para respostas paginadas. Enviado como cabeçalho HTTP.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      },
      "sortByName": {
        "name": "SortByName",
        "in": "header",
        "required": false,
        "description": "Defina como `true` para ordenar os resultados alfabeticamente por nome.",
        "schema": {
          "type": "boolean",
          "default": false
        }
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Token de acesso JWT — utilize como `Authorization: Bearer <token>` nos pedidos seguintes."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Tempo de vida do token em segundos",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "ID de cliente do utilizador autenticado",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Token para obter um novo token de acesso sem reautenticação"
          },
          "application": {
            "type": "string",
            "description": "Nome da integração (apenas para grants de terceiros)",
            "nullable": true
          }
        }
      },
      "PhoneList": {
        "type": "object",
        "properties": {
          "AddressBookId": {
            "type": "integer",
            "description": "Unique identifier of the phone list",
            "example": 42
          },
          "Name": {
            "type": "string",
            "description": "Nome de exibição da lista telefónica",
            "example": "Newsletter subscribers"
          },
          "TotalNumberPhones": {
            "type": "integer",
            "description": "Number of phone numbers in this list",
            "example": 1547
          }
        }
      },
      "PhoneNumber": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificador único da entrada do número de telefone",
            "example": 1001
          },
          "Number": {
            "type": "string",
            "description": "Número de telefone em formato internacional simples (forma armazenada — consulte \"Formato do número de telefone\" na descrição da API para os formatos de entrada aceites)",
            "example": "41791234567"
          },
          "FirstName": {
            "type": "string",
            "description": "Nome próprio do contacto",
            "example": "Alice"
          },
          "LastName": {
            "type": "string",
            "description": "Apelido do contacto",
            "example": "Dupont"
          }
        }
      },
      "SingleSend": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificador único do envio criado",
            "example": 5001
          },
          "Message": {
            "type": "string",
            "description": "O texto da mensagem SMS",
            "example": "Your verification code is 8472"
          },
          "ScheduledTime": {
            "type": "string",
            "format": "date-time",
            "description": "Quando o SMS será (ou foi) enviado",
            "example": "2026-04-15T09:00:00"
          },
          "To": {
            "type": "string",
            "description": "Número de telefone do destinatário",
            "example": "0041791234567"
          },
          "Charge": {
            "type": "string",
            "description": "Créditos efetivamente cobrados por este envio = **créditos do país × número de partes**.\nEx.: um SMS de 1 parte para o Panamá (+507, 3 créditos/SMS) → `\"3\"`; um SMS de 2 partes → `\"6\"`.\n",
            "example": "3"
          },
          "Parts": {
            "type": "integer",
            "description": "Número de segmentos de SMS (partes GSM 03.38) em que a mensagem foi dividida.",
            "example": 1
          }
        }
      },
      "BulkSend": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificador único do envio em massa criado",
            "example": 6001
          },
          "Message": {
            "type": "string",
            "description": "O texto da mensagem SMS",
            "example": "Spring sale — 20% off all products this weekend!"
          },
          "ScheduledTime": {
            "type": "string",
            "format": "date-time",
            "description": "Quando a campanha SMS será (ou foi) enviada",
            "example": "2026-04-20T10:00:00"
          },
          "To": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Lista de IDs de listas de contactos visadas por este envio",
            "example": [
              "42"
            ]
          },
          "Charge": {
            "type": "string",
            "description": "Total de créditos cobrados pelo envio completo = **Σ (créditos do país × partes)**\nsobre todos os números da lista de contatos.\n",
            "example": "150"
          },
          "Parts": {
            "type": "integer",
            "description": "Número de segmentos de SMS (partes GSM 03.38) por mensagem.",
            "example": 1
          }
        }
      },
      "CreditBalance": {
        "type": "object",
        "properties": {
          "TotalCredits": {
            "type": "number",
            "description": "Saldo de créditos SMS restante (créditos do plano + créditos mensais).\n\nÉ uma contagem de créditos, não um número de mensagens: um SMS custa\n`créditos do país × número de partes` — ver «Custo em créditos de um SMS» na\ndescrição da API.\n",
            "example": 5000
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "Error": {
            "type": "string",
            "description": "Mensagem de erro legível por humanos",
            "example": "Malformed Input"
          },
          "Code": {
            "type": "integer",
            "description": "Código de erro específico do 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`, nenhum evento é entregue. Desativado automaticamente após 10 falhas consecutivas.",
            "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 foi tentada a última entrega",
            "example": "2026-07-21T18:56:07.653"
          },
          "last_delivery_status": {
            "type": "integer",
            "nullable": true,
            "description": "Estado HTTP devolvido pelo seu endpoint na última entrega",
            "example": 200
          },
          "consecutive_failures": {
            "type": "integer",
            "description": "Reposto a 0 no primeiro sucesso; aos 10 o webhook é desativado automaticamente",
            "example": 0
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipos de eventos subscritos. Um array vazio significa todos os eventos desta API.",
            "example": [
              "sms.delivered",
              "sms.failed"
            ]
          }
        }
      },
      "WebhookList": {
        "type": "object",
        "description": "Envelope devolvido por `GET /webhooks`.",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "total": {
            "type": "integer",
            "description": "Número total de webhooks na conta",
            "example": 2
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS (HTTP recusado em produção)",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "Lista de tipos de evento a subscrever (consulte o catálogo acima). Utilize `[\"*\"]` para subscrever todos os eventos desta 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": "Segredo HMAC. **Mostrado apenas uma vez aqui, nunca mais.** Guarde-o no lado do servidor.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Actualização parcial — todos os campos são opcionais.",
        "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": "Defina `true` para reactivar um webhook desactivado automaticamente após o seu endpoint ter sido corrigido."
          }
        }
      },
      "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": "Obtenha um token JWT Bearer para autenticar todas as restantes chamadas à API. O endpoint\nSMS `/token` é um redireccionamento 307 para o emissor canónico `/v3/token` —\no seu cliente HTTP segue o redireccionamento de forma transparente (o método POST e\no corpo do pedido são preservados).\n"
    },
    {
      "name": "Account",
      "description": "Verifique o seu saldo de créditos SMS, a quota mensal da API e o estado da conta."
    },
    {
      "name": "Send SMS",
      "description": "Envie mensagens SMS — quer um **SMS transaccional único** para um destinatário,\nquer uma **campanha em massa** para uma lista de contactos completa.\n"
    },
    {
      "name": "Lists",
      "description": "Faça a gestão das listas de contactos SMS. Uma lista de contactos agrupa números de telefone para envios em massa.\nPode criar até 1000 listas por conta (mesmo limite nas três API Mailpro e na app).\n"
    },
    {
      "name": "Phone Numbers",
      "description": "Faça a gestão dos números de telefone individuais dentro de uma lista de contactos — adicione, actualize e remova entradas."
    },
    {
      "name": "Credit",
      "description": "Consulte o saldo de créditos SMS restante para a sua conta (separado da quota mensal de pedidos à API — consulte `/account/limits`)."
    },
    {
      "name": "History",
      "description": "Consulte o registo completo das campanhas SMS passadas."
    },
    {
      "name": "Import",
      "description": "Carregue um ficheiro CSV ou XLSX para importar números de telefone em massa para uma lista de contactos.\nO ficheiro é colocado em fila para processamento assíncrono — acompanhe a conclusão através do\n`ImportJobId` devolvido ou através do callback opcional `webhook_url`.\n"
    },
    {
      "name": "Webhooks",
      "description": "Subscreva o seu servidor para notificações de eventos SMS em tempo real. O Mailpro envia\num payload JSON assinado por HMAC para o seu URL assim que o evento subscrito\nocorrer. Consulte a secção \"Webhooks\" na introdução para o catálogo completo de eventos,\no envelope do payload, os excertos de verificação de assinatura e a política de repetição.\n"
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getSmsAccessToken",
        "summary": "Obter token de acesso (redireccionamento 307 para /v3/token)",
        "security": [],
        "description": "Obtém um token JWT Bearer utilizando as credenciais do cliente Mailpro.\nEnvie o `access_token` devolvido como `Authorization: Bearer <token>` em todos os\npedidos subsequentes. O mesmo token é igualmente válido na API CRM v3 e\nna API Email v2.\n\n> **⚙ Detalhe de implementação** — `POST /sms/token` é um **redireccionamento\n> temporário 307** para `POST /v3/token` (configurado na camada de reescrita do\n> `web.config` do IIS). O HTTP 307 preserva tanto o **método** (`POST`) como\n> o **corpo do pedido**, pelo que qualquer cliente HTTP em conformidade com a norma\n> segue o redireccionamento de forma transparente — continua a enviar pedidos para `/sms/token` e recebe\n> de volta um JWT válido. Não há lógica de emissão de tokens duplicada; a\n> API SMS nunca emite tokens por si própria.\n\n### Tipos de grant suportados\n| Tipo de grant | Caso de uso |\n|------------|----------|\n| `password` | Integração padrão — nome de utilizador + chave de API |\n| `refresh_token` | Renovar um token de acesso que está a expirar sem reautenticação |\n| `client_credentials` | Servidor-a-servidor apenas com o ID de cliente |\n\n### Tempo de vida do token\n- Token de acesso: **30 dias**\n- Refresh token: **90 dias**\n\nUtilize `grant_type=refresh_token` para renovar o token de acesso sem\nreautenticação. Guarde os tokens no lado do servidor (Vault, variáveis de ambiente); nunca\nos incorpore em JavaScript de browser ou em binários de aplicações móveis. Consulte a documentação\ndo `/token` da API CRM v3 para a nota de segurança completa.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "password",
                      "refresh_token",
                      "client_credentials"
                    ],
                    "example": "password"
                  },
                  "username": {
                    "type": "string",
                    "description": "O seu nome de utilizador Mailpro (email). Obrigatório para o grant `password`.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "A sua chave de API Mailpro (formato GUID). Obrigatório para o grant `password`.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Refresh token anterior. Obrigatório para o grant `refresh_token`."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "O seu ID de cliente Mailpro (inteiro). Obrigatório para o grant `client_credentials`.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token emitido com sucesso. Devolvido por `POST /v3/token` após o\nseguimento transparente do 307 — o seu cliente HTTP vê um 200 normal com\na mesma forma de corpo que receberia directamente do endpoint de token 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": "Redireccionamento temporário para `POST /v3/token`, emitido pela regra de reescrita\ndo IIS no `web.config`. Os clientes HTTP em conformidade com a norma seguem este redireccionamento\nautomaticamente e preservam o método POST original + o corpo do formulário.\nVisível apenas para clientes que desactivam explicitamente o seguimento de redireccionamentos\n(p. ex. `curl --max-redirs 0`).\n",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "example": "https://api.mailpro.com/v3/token"
              }
            }
          },
          "400": {
            "description": "Credenciais inválidas ou tipo de grant não suportado",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Credenciais erradas",
                    "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": "Obter saldo de créditos SMS",
        "description": "Devolve o saldo actual de créditos SMS para a sua conta.\nOs créditos SMS são consumidos no momento do envio. Um SMS padrão (≤160 caracteres GSM-7)\ncusta 1 crédito. Mensagens mais longas ou mensagens com caracteres especiais podem custar mais.\n\n> Nota: isto devolve o seu **saldo de créditos de envio SMS**, não a sua quota de pedidos à API.\n> Para a quota da API consulte `GET /account/limits.{format}`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo de créditos devolvido com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalance"
                },
                "example": {
                  "TotalCredits": 5000
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSmsAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obter quota mensal da API",
        "description": "Devolve a quota mensal de pedidos à API para o cliente autenticado.\n\n**Cálculo da quota:** o limite é calibrado a partir dos créditos\nde subscrição de email (tipicamente `subscription_credits × 5`). Para\num plano de 10 000 emails/mês, isto resulta num orçamento mensal\nde 50 000 pedidos. Reinicia na **data de aniversário da subscrição** (e não no\ndia 1 do mês de calendário).\n\n**O que consome créditos:**\n- Todos os pedidos à API autenticados para endpoints `v2`, `v3` ou `sms`.\n- Todos os eventos de webhook despachados para um endpoint subscrito.\n\n**O que é GRATUITO (não consome créditos):**\n- Endpoints `/health`.\n- Pedidos que falham com `401`, `403` ou `429`.\n- Eventos de webhook para clientes sem subscrição correspondente.\n\nA quota é **partilhada entre as 3 APIs Mailpro** (`v2`, `v3`, `sms`)\n— um cliente = um orçamento mensal em toda a plataforma. Os envios SMS\nconsomem adicionalmente o saldo de créditos SMS dedicado\n(`GET /credit/get.{format}`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Instantâneo da quota",
            "content": {
              "application/json": {
                "example": {
                  "monthlyLimit": 50000,
                  "remaining": 32847,
                  "used": 17153,
                  "isFree": false,
                  "remainedSendsForFree": null
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Nenhum registo de quota encontrado (conta recém-criada; a linha será criada no primeiro pedido autenticado)."
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listSmsHistory",
        "security": [
          {
            "OAuth2": [
              "sms:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar histórico de envios SMS",
        "description": "Devolve um registo paginado de todas as campanhas SMS passadas enviadas a partir desta conta.\nOs resultados estão ordenados por data descendente (mais recente primeiro).\nPaginação: `NumberOfRecords` e `PageNumber` (cabeçalhos ou query, 5000 por página por predefinição).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista do histórico devolvida com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "Id": {
                            "type": "integer",
                            "description": "Identificador do envio a que pertence esta linha",
                            "example": 583294
                          },
                          "DateSent": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Carimbo de data/hora de entrega comunicado pelo operador",
                            "example": "2026-07-17T18:56:39.813"
                          },
                          "Message": {
                            "type": "string",
                            "example": "Your verification code is 8472"
                          },
                          "Charge": {
                            "type": "number",
                            "description": "Créditos cobrados por esta linha = **créditos do país × número de partes**\n(ex.: 3 para um SMS de 1 parte para o Panamá). Anteriormente sempre `1`.\n",
                            "example": 3
                          },
                          "Parts": {
                            "type": "integer",
                            "description": "Número de segmentos de SMS (partes GSM 03.38) em que a mensagem foi dividida.",
                            "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": "Credenciais inválidas"
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listSmsLists",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar listas de contactos telefónicos",
        "description": "Devolve todas as listas de contactos SMS da conta.\nUtilize os valores `Id` devolvidos ao enviar campanhas SMS em massa ou ao adicionar números de telefone.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Listas telefónicas devolvidas com sucesso",
            "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": "Credenciais inválidas"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addSmsList",
        "summary": "Criar uma lista de contactos",
        "description": "Cria uma nova lista de contactos SMS com o nome indicado.\nA lista começa vazia — adicione números de telefone com `POST /phone/add`.\nMáximo de 1000 listas por conta (mesmo limite nas três API Mailpro e na app). Devolve HTTP 422 se o limite for atingido.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "name": {
                    "type": "string",
                    "description": "Nome de exibição para a nova lista de contactos",
                    "example": "Spring campaign 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista de contactos criada com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneList"
                },
                "example": {
                  "Id": 44,
                  "Name": "Spring campaign 2026",
                  "NumberPhones": 0
                }
              }
            }
          },
          "400": {
            "description": "Falta um campo obrigatório (name)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editSmsList",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Renomear uma lista de contactos",
        "description": "Actualiza o nome de exibição de uma lista de contactos SMS existente.\nOs números de telefone na lista não são afectados.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID da lista de contactos a renomear (obtido em `/list/list`)",
                    "example": 42
                  },
                  "name": {
                    "type": "string",
                    "description": "Novo nome de exibição para a lista de contactos",
                    "example": "Spring campaign 2026 — updated"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista de contactos renomeada com sucesso"
          },
          "400": {
            "description": "Falta um campo obrigatório",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteSmsList",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar uma lista de contactos",
        "description": "Elimina permanentemente uma lista de contactos SMS **e todos os números de telefone que ela contém**.\nEsta acção não pode ser anulada.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID da lista de contactos a eliminar",
                    "example": 42
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista de contactos eliminada com sucesso"
          },
          "400": {
            "description": "Falta address_book_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/phone/list.{format}": {
      "get": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "listPhones",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar números de telefone numa lista de contactos",
        "description": "Devolve uma lista paginada de números de telefone numa lista de contactos específica.\nUtilize `address_book_id` para especificar a lista a obter.\nPaginação: `NumberOfRecords` e `PageNumber` (5000 por página por predefinição, página 1).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "address_book_id",
            "in": "query",
            "required": true,
            "description": "ID da lista de contactos a partir da qual obter os números de telefone",
            "schema": {
              "type": "integer"
            },
            "example": 42
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "$ref": "#/components/parameters/sortByName"
          }
        ],
        "responses": {
          "200": {
            "description": "Números de telefone devolvidos com sucesso",
            "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": "Credenciais inválidas"
          }
        }
      }
    },
    "/phone/add.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "addPhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Adicionar número(s) de telefone a uma lista",
        "description": "Adiciona um ou mais números de telefone a uma lista de contactos.\n\n**Número único:** utilize o campo `number`.\n\n**Importação em massa:** utilize o campo `phone_list` com os números separados por ponto e vírgula:\n`+41791234567;+33612345678;0049301234567`\n\nOs números de telefone aceitam o formato `+`, `00` ou simples — consulte **Formato do número de telefone**\nna descrição da API para a lista completa de entradas aceites / rejeitadas.\nOs números duplicados são silenciosamente ignorados, salvo se `force=1` estiver definido.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID da lista de contactos à qual adicionar o(s) número(s)",
                    "example": 42
                  },
                  "number": {
                    "type": "string",
                    "description": "Número de telefone único. Aceita `+41…`, `0041…` ou `41…` com ou sem\nseparadores (espaços, traços, pontos, barras, parênteses). Consulte\n**Formato do número de telefone** na descrição da API.\nUtilize este **OU** `phone_list` — não ambos.\n",
                    "example": "+41791234567"
                  },
                  "phone_list": {
                    "type": "string",
                    "description": "Lista de números de telefone separados por ponto e vírgula para importação em massa.\nUtilize este **OU** `number` — não ambos.\nExemplo: `0041791234567;0033612345678`\n",
                    "example": "0041791234567;0033612345678;0049301234567"
                  },
                  "firstname": {
                    "type": "string",
                    "description": "Nome próprio do contacto (opcional, apenas para número único)",
                    "example": "Alice"
                  },
                  "lastname": {
                    "type": "string",
                    "description": "Apelido do contacto (opcional, apenas para número único)",
                    "example": "Dupont"
                  },
                  "force": {
                    "type": "integer",
                    "description": "Defina como `1` para adicionar um número mesmo que tenha sido previamente cancelado ou já exista.\nPredefinição: `0` (os duplicados são ignorados).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Número(s) de telefone adicionado(s) com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                },
                "example": {
                  "Id": 1003,
                  "Number": "0041791234567",
                  "FirstName": "Alice",
                  "LastName": "Dupont"
                }
              }
            }
          },
          "400": {
            "description": "Falta um campo obrigatório",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/phone/edit.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "editPhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Actualizar uma entrada de número de telefone",
        "description": "Actualiza o número de telefone e/ou os dados de contacto de uma entrada existente.\nUtilize `number_id` (obtido em `/phone/list`) para identificar a entrada a actualizar.\nApenas os campos fornecidos no pedido são actualizados.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "number_id": {
                    "type": "integer",
                    "description": "ID da entrada do número de telefone a actualizar (obtido em `/phone/list`)",
                    "example": 1001
                  },
                  "number": {
                    "type": "string",
                    "description": "Novo número de telefone. Aceita `+41…`, `0041…` ou `41…` com ou sem separadores. Consulte **Formato do número de telefone** na descrição da API.",
                    "example": "+41791234568"
                  },
                  "firstname": {
                    "type": "string",
                    "description": "Novo nome próprio para o contacto",
                    "example": "Alice"
                  },
                  "lastname": {
                    "type": "string",
                    "description": "Novo apelido para o contacto",
                    "example": "Dupont-Martin"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Entrada do número de telefone actualizada com sucesso"
          },
          "400": {
            "description": "Falta number_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/phone/del.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "deletePhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remover um número de telefone de uma lista",
        "description": "Remove permanentemente uma entrada específica de número de telefone da sua lista de contactos.\nUtilize `number_id` (obtido em `/phone/list`) para identificar a entrada.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "number_id": {
                    "type": "integer",
                    "description": "ID da entrada do número de telefone a eliminar (obtido em `/phone/list`)",
                    "example": 1001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Número de telefone removido com sucesso"
          },
          "400": {
            "description": "Falta number_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/add.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendBulkSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar SMS em massa para uma lista de contactos",
        "description": "Envia uma mensagem SMS para **todos os números de telefone** de uma lista de contactos.\nSuporta agendamento: defina `scheduled_time` para uma data futura para enviar mais tarde,\nou omita-o para enviar imediatamente.\n\n**Consumo de créditos:** os créditos são debitados no momento do envio.\nMensagens longas (>160 caracteres GSM-7) são divididas em várias partes,\ncada uma consumindo créditos adicionais.\n\nA resposta devolve `{ \"Error\": \"Insufficient Credit\", \"Code\": 202 }` se\na conta não tiver créditos suficientes.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "message": {
                    "type": "string",
                    "description": "Texto da mensagem SMS. Mantenha abaixo dos 160 caracteres para um SMS de parte única.\nCaracteres fora do alfabeto GSM-7 (p. ex. chinês, árabe, emoji)\nmudam a codificação para Unicode, reduzindo o limite para 70 caracteres por parte.\n",
                    "example": "Flash sale today only — 30% off all orders. Shop now at mailpro.com/shop"
                  },
                  "to": {
                    "type": "integer",
                    "description": "ID da lista de contactos para a qual enviar (obtido em `/list/list`)",
                    "example": 42
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Agende o envio para uma data/hora futura (ISO 8601).\nOmita ou deixe vazio para enviar imediatamente.\n",
                    "example": "2026-04-20T10:00:00"
                  },
                  "shorten_urls": {
                    "type": "boolean",
                    "default": false,
                    "description": "Defina `true` para substituir cada hiperligação da mensagem por uma ligação curta `https://mailp.ro/m/...`: menos caracteres, logo por vezes menos partes de SMS faturadas. Uma hiperligação que não possa ser encurtada fica como está."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envio SMS em massa criado com sucesso",
            "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": "Créditos SMS insuficientes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Insufficient Credit",
                  "Code": 202
                }
              }
            }
          },
          "400": {
            "description": "Falta um campo obrigatório",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/add_single.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendSingleSmsGet",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar um SMS único (GET)",
        "description": "Envia um único SMS para um destinatário através de um pedido GET.\nÚtil para integrações simples nas quais POST não está disponível.\nAs credenciais e a mensagem são passadas como parâmetros de query.\n\n**Nota:** evite utilizar GET para mensagens sensíveis — os parâmetros de query aparecem nos registos do servidor.\nPrefira `POST /send/add_single`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Número de telefone do destinatário. Aceita `+41…`, `0041…` ou `41…` com ou sem separadores. Consulte **Formato do número de telefone** na descrição da API.",
            "schema": {
              "type": "string"
            },
            "example": "+41791234567"
          },
          {
            "name": "message",
            "in": "query",
            "required": true,
            "description": "Texto da mensagem SMS (máximo 160 caracteres para codificação padrão)",
            "schema": {
              "type": "string"
            },
            "example": "Your appointment is confirmed for tomorrow at 10:00."
          },
          {
            "name": "scheduled_time",
            "in": "query",
            "description": "Agende o envio (ISO 8601). Omita para enviar imediatamente.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "shorten_urls",
            "in": "query",
            "description": "Defina `true` para substituir cada hiperligação da mensagem por uma ligação curta `https://mailp.ro/m/...`: menos caracteres, logo por vezes menos partes de SMS faturadas. Uma hiperligação que não possa ser encurtada fica como está.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SMS enviado (ou agendado) com sucesso",
            "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": "Créditos SMS insuficientes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "400": {
            "description": "Falta um parâmetro obrigatório",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      },
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendSingleSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar um SMS único",
        "description": "Envia uma única mensagem SMS para um número de telefone destinatário.\nSuporta agendamento através de `scheduled_time`.\n\n**Consumo de créditos:** os créditos são debitados no momento do envio.\nO campo `Charge` na resposta mostra quantos créditos foram consumidos.\n\nA resposta devolve `{ \"Error\": \"Insufficient Credit\", \"Code\": 202 }` se\na conta não tiver créditos suficientes.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "message": {
                    "type": "string",
                    "description": "Texto da mensagem SMS",
                    "example": "Your verification code is 8472. Valid for 10 minutes."
                  },
                  "to": {
                    "type": "string",
                    "description": "Número de telefone do destinatário. Aceita `+41…`, `0041…` ou `41…` com ou sem separadores. Consulte **Formato do número de telefone** na descrição da API.",
                    "example": "+41791234567"
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Agende o envio para uma hora futura. Omita para enviar imediatamente.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "shorten_urls": {
                    "type": "boolean",
                    "default": false,
                    "description": "Defina `true` para substituir cada hiperligação da mensagem por uma ligação curta `https://mailp.ro/m/...`: menos caracteres, logo por vezes menos partes de SMS faturadas. Uma hiperligação que não possa ser encurtada fica como está."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS enviado (ou agendado) com sucesso",
            "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": "Créditos SMS insuficientes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Insufficient Credit",
                  "Code": 202
                }
              }
            }
          },
          "400": {
            "description": "Falta um campo obrigatório",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "listSmsSends",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar campanhas SMS",
        "description": "Devolve a lista de campanhas SMS (envios em massa) para a conta.\nPaginação através dos cabeçalhos `NumberOfRecords` e `PageNumber`.\n\nUtilize `type_to` para filtrar por tipo de envio:\n- `0` (predefinição) — envios em massa para uma lista\n- `1` — envios individuais únicos\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type_to",
            "in": "query",
            "description": "Filtro do tipo de envio:\n- `0` (predefinição) — envios em massa para uma lista de contactos\n- `1` — envios únicos para números individuais\n",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de campanhas SMS devolvida com sucesso",
            "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": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "deleteSmsSend",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar ou eliminar um envio SMS",
        "description": "Cancela um envio SMS **agendado pendente**, ou elimina um envio **concluído** do histórico.\nApenas os envios agendados para o futuro podem ser cancelados. Os envios em curso não podem ser parados.\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": "O seu ID de cliente Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "A sua chave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "id_send": {
                    "type": "integer",
                    "description": "ID do envio SMS a cancelar ou eliminar (obtido em `/send/list`)",
                    "example": 6001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envio SMS cancelado ou eliminado com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "Falta id_send",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "500": {
            "description": "Falha na eliminação (envio não encontrado ou já processado)",
            "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": "Listar os meus envios SMS agendados",
        "description": "Devolve os envios SMS (únicos ou de campanha) agendados para uma data futura que\nainda não foram despachados. Útil antes de invocar `/cancel` ou `/reschedule`.\n\nOs registos são ordenados por `scheduled_time` ascendente.\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": "Lista de envios SMS agendados",
            "content": {
              "application/json": {
                "example": [
                  {
                    "Id": 9001,
                    "Message": "Black Friday: 30% off until midnight.",
                    "ScheduledTime": "2026-11-27T12:00:00",
                    "To": "+33671234567"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/{id_send}/cancel.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "cancelScheduledSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar um envio SMS agendado",
        "description": "Cancela um SMS agendado que ainda não foi despachado. Se o envio já tiver\nsido processado (ou não existir / pertencer a outro cliente),\ndevolve **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": "Envio cancelado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 9001
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "409": {
            "description": "Já despachado ou não encontrado",
            "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": "Reagendar um envio SMS agendado",
        "description": "Actualiza a data planeada de um SMS agendado que ainda não foi despachado.\nA nova data tem de estar **no futuro** e **dentro de 90 dias**.\n\n**Nome do campo de data:** a API aceita `scheduled_time` (principal) bem como\nos aliases legados `PlanDate`, `date_planned` e `DatePlanned`. Forneça\nqualquer um deles — o primeiro não nulo é utilizado.\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": "Forneça um de `scheduled_time`, `PlanDate`, `date_planned` ou `DatePlanned`.",
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "example": "a1b2c3d4-..."
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Nome do campo principal.",
                    "example": "2026-12-31T14:30:00"
                  },
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias legado aceite por compatibilidade retroactiva."
                  },
                  "date_planned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias legado aceite por compatibilidade retroactiva."
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias legado aceite por compatibilidade retroactiva."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envio reagendado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 9001,
                  "NewScheduledTime": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "scheduled_time em falta ou inválido"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "409": {
            "description": "Já despachado, não encontrado, ou nova data fora do intervalo",
            "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": "Carregar um ficheiro de números de telefone (CSV / XLSX) para importação em massa",
        "description": "Carregue um ficheiro CSV ou XLSX para importar números de telefone para uma lista de contactos.\nO ficheiro é armazenado e colocado em fila para processamento assíncrono — o endpoint\ndevolve imediatamente um `ImportJobId`.\n\n**Tipo de pedido:** `multipart/form-data`\n\n**Campos de formulário obrigatórios:**\n- `id_client` (inteiro) — o seu ID de cliente Mailpro\n- `api_key` (string) — a sua chave de API\n- `id_list` (inteiro) — ID da lista de contactos de destino\n- `file` (binário) — o ficheiro CSV ou XLSX a carregar\n\n**Opcional:**\n- `webhook_url` (string) — URL HTTPS invocado quando o processamento termina.\n  Recebe um payload JSON com o estado final (success / failed) e\n  contagens das linhas importadas / ignoradas / inválidas.\n\n**Formato do ficheiro:**\n- Codificado em UTF-8\n- Primeira linha = cabeçalhos (um tem de ser `Phone` ou `PhoneNumber` — sem distinção entre maiúsculas e minúsculas)\n- Números em formato internacional (E.164), p. ex. `+41791234567`\n- Tamanho máximo do ficheiro: 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 da lista de contactos de destino",
                    "example": 11088
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Ficheiro CSV ou XLSX (UTF-8, máximo 50 MB)"
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL de callback invocado quando o processamento termina",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ficheiro aceite e colocado em fila",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 15,
                  "InternalName": "230575-20260420142616-phones.csv"
                }
              }
            }
          },
          "400": {
            "description": "Nenhum ficheiro carregado ou id_list em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "500": {
            "description": "Erro de servidor ou de armazenamento"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Serviço de gestão de webhooks (separado do anfitrião principal da API)"
        }
      ],
      "get": {
        "summary": "Listar webhooks",
        "description": "Devolve todos os webhooks configurados na conta autenticada.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array de webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "items": [
                    {
                      "id": 14,
                      "url": "https://example.com/hooks/mailpro",
                      "description": "Integração com o 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": "Credenciais inválidas"
          }
        }
      },
      "post": {
        "summary": "Criar um webhook",
        "description": "Cria uma nova subscrição de webhook. A resposta contém um `secret` que\né **mostrado apenas uma vez** — guarde-o imediatamente, no lado do servidor. Utilize-o para\nverificar a assinatura HMAC de cada payload recebido.\n\n**Limites**: máximo de 20 webhooks por conta, máximo de 50 eventos por 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": "Integração com o Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook criado — o `secret` é devolvido apenas aqui",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "sms.delivered",
                    "sms.failed"
                  ],
                  "description": "Integração com o 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, lista de eventos inválida ou limite excedido"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Serviço de gestão de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "summary": "Obter um webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "O webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      },
      "put": {
        "summary": "Actualizar um webhook",
        "description": "Actualização parcial — apenas os campos enviados são modificados.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook actualizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "Payload inválido"
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      },
      "delete": {
        "summary": "Eliminar um webhook",
        "description": "Elimina permanentemente o webhook e o seu histórico de entregas completo.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Eliminado"
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Serviço de gestão de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Enviar um evento de teste",
        "description": "Coloca em fila um evento `ping` imediato (ou qualquer outro tipo de evento através do\ncampo `eventType` no corpo) para o seu endpoint. Útil para verificar a acessibilidade\ne a verificação da assinatura antes de confiar em eventos reais.\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 colocado em fila para despacho",
            "content": {
              "application/json": {
                "example": {
                  "deliveryId": 1234,
                  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
                  "eventType": "ping"
                }
              }
            }
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Serviço de gestão de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Rotacionar o segredo HMAC",
        "description": "Gera um novo segredo HMAC e invalida o antigo imediatamente.\nO novo segredo é devolvido **uma vez** na resposta — guarde-o. Todas as\nentregas a partir deste momento serão assinadas com o novo segredo.\n\nUtilize esta opção se suspeitar que o seu segredo foi comprometido.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Novo segredo (visível uma única vez)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
                }
              }
            }
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Serviço de gestão de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "in": "query",
          "name": "limit",
          "schema": {
            "type": "integer",
            "default": 50,
            "maximum": 200
          }
        },
        {
          "in": "query",
          "name": "cursor",
          "schema": {
            "type": "integer",
            "format": "int64"
          },
          "description": "Cursor de paginação (= último ID de entrega visto). Devolve entregas com `id < cursor`."
        }
      ],
      "get": {
        "summary": "Listar tentativas de entrega",
        "description": "Devolve o histórico de tentativas de despacho para este webhook (retenção de 30 dias).\nÚtil para depuração — que eventos foram enviados, códigos de estado recebidos,\ncontagens de tentativas, mensagens de erro.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array de tentativas de entrega (mais recentes primeiro)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Serviço de gestão de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "in": "path",
          "name": "deliveryId",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Repetir uma entrega",
        "description": "Coloca em fila uma nova tentativa de entrega com o mesmo payload do original.\nÚtil para voltar a desencadear uma entrega que falhou após corrigir o seu endpoint.\nÉ criada uma NOVA linha `Webhook_Delivery` (o original é preservado\npara fins de auditoria). A repetição segue a política de repetição padrão\n(mesmo agendamento de backoff, mesma regra de desactivação automática às 10 falhas).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Repetição colocada em fila",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook ou entrega não encontrados"
          }
        }
      }
    }
  }
}