{
  "openapi": "3.0.3",
  "info": {
    "title": "API de Email Mailpro™ v2",
    "version": "2",
    "description": "A API Email v2 da Mailpro™ permite-lhe gerir programaticamente listas de contactos, modelos de\nemail, endereços de remetente e campanhas — e enviar emails em massa e transacionais.\n\n## Autenticação\n\nCada endpoint aceita **três métodos de autenticação**. Utilize o que melhor se adequar\nà sua stack.\n\n- **OAuth 2.0** — tokens com scopes, revogáveis, para aplicações de terceiros e\n  plataformas de integração (Zapier, Make, n8n). É o único método que pode confiar a\n  um terceiro. **Os tokens OAuth são controlados por scope em cada endpoint** (ver abaixo).\n- **Bearer JWT** (legado) — um token HMAC obtido através de `POST /token`, sem scopes.\n- **IdClient + ApiKey** (legado) — identificador de cliente + chave API.\n\n> O Bearer JWT legado e IdClient+ApiKey continuam a funcionar sem alterações e **não** estão\n> sujeitos aos scopes. Apenas os tokens de acesso OAuth 2.0 estão sujeitos aos controlos de scope por endpoint\n> indicados em cada operação abaixo.\n\n### Método 1 — OAuth 2.0 (recomendado para integrações)\n\nA Mailpro utiliza **um único** servidor de autorização OAuth 2.0 para todas as suas API, numa\nsuperfí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\n**mesmo** token funciona nesta API Email v2, na CRM v3 e na SMS. Os\nendpoints que pode invocar dependem dos **scopes** do token, não do URL base\nda API. Emissor (claim `iss`): `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Autorização | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / renovação | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Descoberta | `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). Duração do token de acesso: **20 min**; token de atualização: **30 dias**\n(deslizantes, de utilização única); código de autorização: **60 s**.\n\n**Início rápido — obter um token e invocar esta API** (substitua os valores; nunca\nfaça commit de um segredo 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=email:send email:read\"\n```\n\nInvoque depois esta API com `Authorization: Bearer ACCESS_TOKEN`. O mesmo token\nfunciona nas API CRM v3 e SMS. Um token a que falte o scope exigido por um\nendpoint recebe **403 `insufficient_scope`**. Percurso completo e catálogo de scopes:\nconsulte a documentação da API **CRM v3** › Autenticação. Scopes úteis para o email:\n`email:send`, `email:read`, `email:templates:read`, `email:templates:write`,\n`contacts:read`, `contacts:write`, `account:read`.\n\n### Método 2 — Bearer JWT (legado)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nObtenha um token através de `POST /token` (codificado como formulário, OAuth2 password grant):\n\n```\nPOST https://api.mailpro.com/v2/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password&username=YOUR_USERNAME&password=YOUR_API_KEY\n```\n\nO mesmo token também é válido na API CRM v3 e na API SMS —\nautentique-se uma vez, invoque qualquer API. Os tokens são válidos por **30 dias** por predefinição;\nutilize `grant_type=refresh_token` para renovar sem ter de se autenticar novamente. Sem scopes\n— prefira OAuth 2.0 para as integrações instaláveis.\n\n### Método 3 — IdClient + ApiKey\n\nDuas credenciais:\n\n| Parâmetro  | Tipo    | Descrição |\n|------------|---------|-------------|\n| `IdClient` | integer | O seu ID numérico de cliente Mailpro, disponível em **Definições → Acesso à API** |\n| `ApiKey`   | string  | A sua chave de API, disponível em **Definições → Acesso à API** |\n\nEnvie-as num destes locais — escolha um:\n\n1. **Cabeçalhos HTTP (recomendado)** — `IdClient: 12345` e `ApiKey: a1b2c3d4-…`.\n   Os URLs são registados pelos servidores web, CDN e proxies, pelo que uma chave na query string\n   pode ser exposta nos registos de acesso. Os cabeçalhos não são registados.\n2. **Query string (legado, ainda funciona)** — `?IdClient=12345&ApiKey=…`.\n   Mantida por questões de retrocompatibilidade com integrações existentes. Mude para\n   cabeçalhos assim que puder.\n3. **Corpo do formulário (apenas POST)** — `IdClient=12345&ApiKey=…` em\n   `application/x-www-form-urlencoded`.\n\nSe fornecer credenciais em mais do que um local, o **cabeçalho prevalece**.\n\n### Controlo de scopes OAuth por endpoint (Email v2)\n\nPara os tokens emitidos por OAuth, cada grupo de endpoints exige um scope (a autenticação\nlegada está isenta). Cada operação indica o seu scope em **Authorization**. Resumo:\n\n| Endpoints | Scope exigido |\n|-----------|---------------|\n| `/send/*` (campanhas, transacional, agendamento, teste — exceto `/send/{IdSend}/status`) | `email:send` |\n| `/stats/*` (exceto `/stats/del`), `/history/list`, `/send/{IdSend}/status` | `email:read` |\n| `/message/*`, `/senderEmail/*` (leitura) | `email:templates:read` |\n| `/message/*`, `/senderEmail/*` (add/edit/del), `/stats/del` | `email:templates:write` |\n| `/list/list`, `/email/list` | `contacts:read` |\n| `/list/{add,edit,del}`, `/email/{add,addSingle,edit,del}`, `/import/upload` | `contacts:write` |\n| `/account/*` | `account:read` |\n\nUma recusa por scope devolve **403** com\n`{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }`.\n\n## Formato da resposta\n\nTodos os endpoints suportam `json` (predefinido) e `xml`. Indique o formato no URL:\n- `/email/list.json`\n- `/email/list.xml`\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- As páginas são estáveis: a mesma chamada devolve os mesmos itens, pela mesma ordem, enquanto\n  os dados não mudarem entretanto.\n- Exceção: as listas de mensagens e de histórico com o seu HTML (`bodyHTML=true`) devolvem 10 itens por página.\n- `/email/list` acrescenta `X-Total-Count` (o total real) e `X-Truncated: true` quando restam contactos\n  para além da página.\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## Respostas de erro\n\n| HTTP | Significado |\n|------|---------|\n| 400  | Pedido inválido — parâmetro obrigatório em falta ou inválido |\n| 401  | Não autorizado — `IdClient` ou `ApiKey` inválido |\n| 403  | Proibido — limite da conta atingido (ex.: número máximo de listas) |\n| 404  | Não encontrado — o recurso solicitado não existe |\n| 500  | Erro interno do servidor |\n\nErros resultantes de regras de negócio:\n- `\"Not enough credit available.\"` → 403 — a sua conta não tem créditos de email disponíveis\n- `\"Email address unsubscribed.\"` → 400 — o destinatário cancelou a subscrição\n\n## Acompanhamento da entrega (emails transacionais)\n\nCada email enviado **individualmente** (`POST /send/sendmail`, a CRM API v3, o relay SMTP ou uma automação) recebe um identificador. Pode ser acompanhado até o servidor do destinatário o aceitar ou recusar. As campanhas não são abrangidas aqui: utilize as estatísticas.\n\n1. **Envie**: a resposta de `POST /send/sendmail.{format}` contém o identificador do envio.\n2. **Receba o resultado** (recomendado): os eventos webhook `email.delivered` e `email.bounced` enviam o estado final para o seu servidor assim que é conhecido, sem qualquer consulta.\n3. **Ou consulte**: `GET /send/{IdSend}/status.{format}` devolve o estado atual (tabela abaixo).\n\n| `status` | Significado | Final? |\n|---|---|---|\n| `queued` | Aceite, à espera de envio. | não |\n| `scheduled` | Agendado para mais tarde (`DatePlanned`). | não |\n| `sent` | Entregue pelos nossos servidores, ainda sem resposta do servidor do destinatário. | não |\n| `delivered` | Aceite pelo servidor do destinatário (`DiagCode` = a sua resposta SMTP). | **sim** |\n| `bounced` | Recusado. `BounceType`: `hard` = endereço inválido ou recusa definitiva; `soft` = recusa após novas tentativas (caixa cheia, servidor inacessível…). | **sim** |\n| `not_found` | Identificador desconhecido ou que não pertence à sua conta. | **sim** |\n\n**Consultar sem entrar em ciclo**\n\n- Pare de consultar assim que o estado for **final**: já não vai mudar.\n- Primeira consulta, no mínimo, **5 minutos** após o envio: `delivered` aparece cerca de 5 minutos após a entrega.\n- Depois, **no máximo uma consulta a cada 15 minutos**.\n- Se consultar um envio não final antes de 15 minutos, recebe a mesma resposta com o cabeçalho `Retry-After` (o número de segundos a aguardar), e a chamada não conta para a sua quota.\n- **No máximo 48 horas** após o envio, cada email tem um estado final: depois disso, não consulte mais.\n- `scheduled`: não é preciso consultar antes de `DatePlanned`.\n- **Cada consulta conta para a sua quota de pedidos à API.** Seguindo estas regras, um envio custa no máximo 192 pedidos (4 por hora durante 48 horas), e muito menos na prática, porque para no estado final. O mesmo acompanhamento por webhook custa um único evento.\n\nOs estados são conservados durante **365 dias**.\n\n## Webhooks\n\nA Mailpro™ pode notificar o seu servidor em tempo real quando determinados eventos ocorrem na sua\nconta (um email é entregue, uma campanha termina, um contacto devolve, etc.).\nAo estilo da Stripe — o seu URL recebe um POST assinado com HMAC-SHA256 assim que o\nevento é disparado.\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 através de `POST /webhooks`. A resposta\n   contém um `secret` apresentado **uma única vez** (ao estilo Stripe / GitHub) — guarde-o.\n2. A **Mailpro envia um POST** com um payload JSON assinado para o seu URL assim que um evento corresponda.\n3. **Verifique a assinatura** no lado do servidor com o seu `secret` (excertos abaixo).\n4. **Responda 200–299** em até 10 segundos. Caso contrário, voltamos a tentar com backoff\n   exponencial (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, e depois desistimos).\n\n> **⏱ Atraso de ativação** — após criar, atualizar ou eliminar um webhook, a\n> alteração demora até **10 minutos** a propagar-se pelos servidores da API\n> Mailpro. Durante essa janela, os eventos poderão ainda não corresponder à sua nova subscrição\n> (ou continuar a corresponder a uma que acabou de ser removida). Este é o tempo necessário para\n> atualizar a cache em memória das 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\":       \"email.delivered\",\n  \"created\":    1748194800,\n  \"apiVersion\": \"v2\",\n  \"account\":    { \"id\": 12345, \"name\": \"ACME Corp\" },\n  \"data\":       { \"messageId\": \"...\", \"email\": \"alice@example.com\", \"...\": \"...\" }\n}\n```\n\n| Campo | Formato | Descrição |\n|-------|--------|-------------|\n| `id` | `evt_` + 32 hex | ID único do evento — utilize-o como chave de idempotência no seu lado. |\n| `type` | `<domain>.<verb>` | Tipo de evento canónico. |\n| `created` | Segundos Unix UTC | Incluído na assinatura HMAC. |\n| `apiVersion` | `\"v2\"` | Qual a API Mailpro que publicou o evento. |\n| `account.id` | int | O seu ID de cliente Mailpro (= `IdClient`). |\n| `account.name` | string | O nome da sua conta (útil para depuração no cliente). |\n| `data` | object | Payload do evento — o formato depende do `type` (consulte o catálogo abaixo). |\n\n### Catálogo de eventos\n\n| Evento | Gatilho | Formato de `data` |\n|-------|---------|--------------|\n| `ping` | Teste através de `POST /webhooks/{id}/test` | `{ message }` |\n| `email.processed` | Envio aceite pelo pipeline | `{ messageId, email, campaignId, processedAt }` |\n| `email.delivered` | Um e-mail **individual** foi aceite pelo servidor do destinatário — API v2/v3, SMTP ou Automation (**não** campanhas). Emitido a partir do fluxo de entrega do PowerMTA. | `{ messageId, email, idSending, sendingType, diagCode, deliveredAt }` |\n| `email.opened` | Pixel de rastreio acionado | `{ messageId, email, campaignId, openedAt, ip, userAgent }` |\n| `email.clicked` | Clique numa hiperligação rastreada | `{ messageId, email, campaignId, clickedAt, url, ip, userAgent }` |\n| `email.bounced` | Devolução definitiva ou temporária | `{ messageId, email, campaignId, bouncedAt, bounceType, reason }` |\n| `email.spam_report` | Queixa FBL | `{ messageId, email, campaignId, reportedAt }` |\n| `email.unsubscribed` | Hiperligação de cancelamento clicada | `{ messageId, email, campaignId, unsubscribedAt }` |\n| `email.dropped` | Recusado antes do envio | `{ messageId, email, campaignId, droppedAt, reason }` |\n| `campaign.started` | Início do envio | `{ campaignId, name, totalRecipients, startedAt }` |\n| `campaign.finished` | Todos os destinatários processados | `{ campaignId, name, totalSent, totalFailed, finishedAt }` |\n| `credits.low` | Saldo de créditos de email abaixo do seu limiar de alerta | `{ remaining, threshold }` |\n\nSubscreva todos os eventos desta API passando `[\"*\"]` no array `events`.\n\n### Assinatura HMAC\n\nCada POST transporta 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: email.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### Retentativas 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 | abandonado (entrega marcada como `failed`) |\n\nApós **10 falhas consecutivas** no mesmo webhook, este é **automaticamente\ndesativado** (`isActive: false`) e recebe uma notificação por email. Reative-o\ncom `PUT /webhooks/{id}` assim que o seu endpoint estiver corrigido.\n\n### Sucesso = HTTP 2xx\n\nApenas consideramos o seu webhook bem-sucedido se devolver um estado em `200–299`.\nQualquer 3xx/4xx/5xx ou um timeout (> 10 s) conta como falha e despoleta retentativas.\nSe o seu endpoint estiver permanentemente desativado, devolva `410 Gone` explicitamente — as retentativas\ncontinuam a ocorrer, mas o motivo da falha fica mais claro no seu registo 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/v2",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token JWT Bearer obtido a partir de `POST /v2/token` (form-encoded, password\ngrant). O mesmo token também é válido na API CRM v3 e na API\nSMS — autentique-se uma vez, chame qualquer API.\nIndique-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": "IdClient",
        "description": "O seu ID de cliente Mailpro numérico — transporte **preferencial** (cabeçalho HTTP).\nOs URLs são registados pelos servidores web, Cloudflare e proxies, pelo que as credenciais\nna query string podem fugir para os registos de acesso. Os cabeçalhos não são registados.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "ApiKey",
        "description": "A sua chave de API (GUID) — transporte **preferencial** (cabeçalho HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "IdClient",
        "description": "O seu ID de cliente Mailpro numérico — **legado**, mantido por compatibilidade retroativa.\nMude para o cabeçalho `IdClient` quando puder.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "ApiKey",
        "description": "A sua chave de API (GUID) — **legado**, mantida por compatibilidade retroativa.\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": "query",
        "description": "Itens por página — 5000 por predefinição e no máximo (ver Paginação).",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 50
      },
      "pageNumber": {
        "name": "pageNumber",
        "in": "query",
        "description": "Número da página (começa em 1). O valor predefinido é 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Token JWT de acesso — utilize-o como `Authorization: Bearer <token>` nos pedidos seguintes."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Duração do token em segundos",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "ID do cliente autenticado",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Token para obter um novo token de acesso sem voltar a autenticar"
          },
          "application": {
            "type": "string",
            "description": "Nome da integração (apenas para concessões a terceiros)",
            "nullable": true
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "ListID": {
            "type": "integer",
            "description": "Identificador único da lista",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias legado** — mesmo valor que `ListID`. Devolvido por compatibilidade retroativa com clientes antigos.",
            "example": 101
          },
          "Title": {
            "type": "string",
            "description": "Nome visível da lista",
            "example": "Newsletter — France"
          },
          "Type": {
            "type": "integer",
            "description": "`0` = lista de contactos padrão, `1` = lista negra (para gestão de cancelamentos de subscrição)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "NumberEmails": {
            "type": "integer",
            "description": "Número total de contactos nesta lista",
            "example": 4521
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "description": "Data e hora de criação da lista",
            "example": "2025-01-15T10:30:00"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "IDMessage": {
            "type": "integer",
            "description": "Identificador único do modelo de mensagem",
            "example": 501
          },
          "Subject": {
            "type": "string",
            "description": "Linha de assunto do email",
            "example": "Spring Newsletter — April 2026"
          },
          "Language": {
            "type": "string",
            "description": "Código do idioma utilizado para a localização da hiperligação de cancelamento de subscrição",
            "example": "EN"
          },
          "LinkAlign": {
            "type": "string",
            "description": "Alinhamento horizontal da hiperligação de cancelamento de subscrição",
            "enum": [
              "left",
              "center",
              "right"
            ],
            "example": "center"
          },
          "LinkUp": {
            "type": "integer",
            "description": "Posição da hiperligação de cancelamento de subscrição — `0` = em baixo, `1` = em cima",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "BodyHTML": {
            "type": "string",
            "description": "Conteúdo HTML completo do email (devolvido apenas quando `bodyHTML=true`)",
            "example": "<h1>Welcome!</h1><p>This is our spring newsletter.</p>"
          },
          "UpdateDate": {
            "type": "string",
            "format": "date-time",
            "description": "Data e hora da última modificação do modelo",
            "example": "2026-03-10T14:22:00"
          }
        }
      },
      "SenderEmail": {
        "type": "object",
        "properties": {
          "IDEmailExp": {
            "type": "integer",
            "description": "Identificador único do endereço de email do remetente",
            "example": 201
          },
          "Email": {
            "type": "string",
            "description": "Endereço de email do remetente (tem de ser verificado antes da utilização)",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nome visível apresentado como remetente nos clientes de email dos destinatários",
            "example": "Your Company Newsletter"
          },
          "IsValid": {
            "type": "boolean",
            "description": "`true` se o endereço de email tiver sido verificado pela Mailpro",
            "example": true
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "example": "2025-06-01T09:00:00"
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "IDSend": {
            "type": "integer",
            "description": "Identificador único deste envio / campanha",
            "example": 3001
          },
          "ListID": {
            "type": "integer",
            "description": "ID da lista de destinatários utilizada",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias legado** — mesmo valor que `ListID`.",
            "example": 101
          },
          "IDCampaign": {
            "type": "integer",
            "description": "ID do registo de estatísticas da campanha (se Campaign=1 tiver sido definido no envio)",
            "example": 8001
          },
          "SenderEmail": {
            "type": "string",
            "description": "Endereço de email do remetente",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nome visível do remetente",
            "example": "Your Company Newsletter"
          },
          "DatePlanned": {
            "type": "string",
            "format": "date-time",
            "description": "Data e hora de envio agendadas",
            "example": "2026-04-20T09:00:00"
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Linha de assunto do email",
            "example": "Spring Newsletter — April 2026"
          },
          "NumberCredit": {
            "type": "integer",
            "description": "Número de créditos de email consumidos por este envio",
            "example": 4521
          }
        }
      },
      "HistoryEntry": {
        "type": "object",
        "properties": {
          "IDHistoric": {
            "type": "integer",
            "description": "Identificador único desta entrada do histórico",
            "example": 9001
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Linha de assunto do email enviado",
            "example": "Spring Newsletter — April 2026"
          },
          "DateSend": {
            "type": "string",
            "format": "date-time",
            "description": "Data e hora em que o email foi enviado",
            "example": "2026-04-20T09:00:01"
          },
          "NumberSend": {
            "type": "integer",
            "description": "Número total de emails enviados nesta campanha",
            "example": 4521
          },
          "NumberOpen": {
            "type": "integer",
            "description": "Número de aberturas únicas registadas",
            "example": 1823
          },
          "NumberClick": {
            "type": "integer",
            "description": "Número de cliques únicos em hiperligações registados",
            "example": 342
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "ID do webhook (Mailpro)",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS que recebe os eventos",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipos de eventos subscritos",
            "example": [
              "email.delivered",
              "email.bounced",
              "campaign.finished"
            ]
          },
          "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
          }
        }
      },
      "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 eventos a subscrever (consulte o catálogo acima). Utilize `[\"*\"]` para subscrever todos os eventos desta API.",
            "example": [
              "email.delivered",
              "email.bounced"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 500,
            "example": "Slack integration"
          }
        }
      },
      "WebhookCreateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "Segredo HMAC. **Apresentado uma única vez aqui, nunca mais.** Armazene-o do lado do servidor.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Atualizaçã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 como `true` para reativar um webhook desativado automaticamente depois de corrigir o seu endpoint."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "eventId": {
            "type": "string",
            "example": "evt_8f3a9b2c4d1e5f6789abcdef01234567"
          },
          "eventType": {
            "type": "string",
            "example": "email.delivered"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "retrying",
              "failed"
            ]
          },
          "statusCode": {
            "type": "integer",
            "nullable": true,
            "example": 200
          },
          "responseTimeMs": {
            "type": "integer",
            "nullable": true,
            "example": 142
          },
          "attemptCount": {
            "type": "integer"
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "nextAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Authentication",
      "description": "Obtenha um token JWT Bearer para autenticar todas as outras chamadas à API. O\nendpoint `/token` da v2 é um redirecionamento 307 para o emissor canónico\n`/v3/token` — o seu cliente HTTP segue o redirecionamento de forma transparente (o método\nPOST e o corpo são preservados).\n"
    },
    {
      "name": "Account",
      "description": "Verifique o saldo de créditos de email, a quota mensal da API e o estado da subscrição."
    },
    {
      "name": "Lists",
      "description": "Gira listas (listas de contactos). Uma lista agrupa contactos para campanhas em massa.\n**Máximo de 1000 listas por conta** (mesmo limite nas três API Mailpro e na app).\n`Type 0` = lista padrão. `Type 1` = lista negra (utilizada para gestão de cancelamentos de subscrição).\n"
    },
    {
      "name": "Contacts",
      "description": "Gira contactos de email individuais. Os contactos pertencem a uma ou mais listas.\nUtilize a importação em massa (`/email/add`) para grandes lotes, ou a adição de contacto único (`/email/addSingle`)\npara inscrições individuais com valores de campos personalizados.\n"
    },
    {
      "name": "Messages",
      "description": "Gira modelos de email em HTML. Um modelo de mensagem armazena o assunto do email,\no corpo HTML e a configuração da hiperligação de cancelamento de subscrição.\nOs modelos são reutilizados nas várias campanhas.\n"
    },
    {
      "name": "Campaigns",
      "description": "Envie campanhas de email em massa para uma lista e gira envios agendados.\nUma campanha utiliza um modelo de mensagem e um endereço de remetente.\n"
    },
    {
      "name": "Transactional",
      "description": "Envie emails transacionais avulsos para destinatários individuais.\nAo contrário das campanhas, os emails transacionais não exigem uma lista —\nindica diretamente o email do destinatário e o corpo HTML.\n"
    },
    {
      "name": "Sender Addresses",
      "description": "Liste e gira os endereços de email de remetente validados.\nApenas os endereços verificados podem ser utilizados como endereço `From` nas campanhas.\n"
    },
    {
      "name": "Statistics",
      "description": "Aceda às métricas de desempenho por campanha: aberturas, cliques, devoluções e muito mais.\nEstão disponíveis decomposições detalhadas por hora, dia, país, sistema operativo e cliente de email.\n"
    },
    {
      "name": "History",
      "description": "Consulte o registo completo de todos os envios de email passados.\n"
    },
    {
      "name": "Import",
      "description": "Carregue um ficheiro CSV ou XLSX para importar contactos de email para uma lista em massa.\nO ficheiro é colocado em fila para processamento assíncrono — acompanhe a conclusão através\ndo `ImportJobId` devolvido ou do callback opcional `WebhookUrl`.\n"
    },
    {
      "name": "Webhooks",
      "description": "Subscreva o seu servidor às notificações de eventos em tempo real. A Mailpro envia um POST com\num payload JSON assinado por HMAC para o seu URL assim que o evento subscrito acontecer.\nConsulte a secção \"Webhooks\" na introdução para o catálogo completo de eventos,\no envelope do payload, fragmentos de verificação de assinatura e a política de retentativas.\n"
    },
    {
      "name": "Suppression",
      "description": "Bounces e cancelamentos de subscrição da conta: listar, adicionar, remover."
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getEmailAccessToken",
        "summary": "Obter token de acesso (redirecionamento 307 para /v3/token)",
        "security": [],
        "description": "Obtém um token JWT Bearer utilizando as credenciais de cliente Mailpro.\nIndique o `access_token` devolvido como `Authorization: Bearer <token>` em todos os\npedidos subsequentes. O mesmo token também é válido na API CRM v3 e na\nAPI SMS.\n\n> **⚙ Detalhe de implementação** — `POST /v2/token` é um **redirecionamento 307\n> temporário** para `POST /v3/token` (configurado na camada de reescrita do IIS\n> `web.config`). 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 segue\n> o redirecionamento de forma transparente — continua a fazer POST para `/v2/token` e recebe\n> um JWT válido. Não existe lógica duplicada de emissão de tokens; a\n> API Email v2 nunca emite tokens por si própria.\n\n### Tipos de concessão suportados\n| Tipo de concessão | Caso de utilização |\n|-------------------|--------------------|\n| `password` | Integração padrão — nome de utilizador + chave de API |\n| `refresh_token` | Renovar um token de acesso prestes a expirar sem voltar a autenticar |\n| `client_credentials` | Servidor para servidor apenas com o ID de cliente |\n\n### Duração do token\n- Token de acesso: **30 dias**\n- Token de atualização: **90 dias**\n\nUtilize `grant_type=refresh_token` para renovar o token de acesso sem\nvoltar a autenticar. Armazene os tokens do 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 nota de segurança completa\nna documentação do `/token` da API CRM v3.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "password",
                      "refresh_token",
                      "client_credentials"
                    ],
                    "example": "password"
                  },
                  "username": {
                    "type": "string",
                    "description": "O seu nome de utilizador Mailpro (email). Obrigatório para a concessão `password`.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "A sua chave de API Mailpro (formato GUID). Obrigatória para a concessão `password`.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Token de atualização anterior. Obrigatório para a concessão `refresh_token`."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "O seu ID de cliente Mailpro (inteiro). Obrigatório para a concessão `client_credentials`.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token emitido com sucesso. Devolvido por `POST /v3/token` após o\nencaminhamento 307 transparente — o seu cliente HTTP vê um 200 normal com\no mesmo formato de corpo que receberia diretamente do endpoint de\ntoken v3.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "example": {
                  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "token_type": "bearer",
                  "expires_in": 31535999,
                  "userName": "12345",
                  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "application": null
                }
              }
            }
          },
          "307": {
            "description": "Redirecionamento temporário para `POST /v3/token`, emitido pela regra de reescrita\ndo IIS em `web.config`. Os clientes HTTP em conformidade com a norma seguem este redirecionamento\nautomaticamente e preservam o método POST original + o corpo de formulário.\nVisível apenas para clientes que desativem explicitamente o seguimento de redirecionamentos\n(por exemplo, `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 concessão não suportado",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Credenciais incorretas",
                    "value": {
                      "error": "invalid_grant",
                      "error_description": "The username or password is incorrect."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/account/credits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountCredits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obter saldo de créditos de email",
        "description": "Devolve o saldo de créditos de email restantes da sua conta Mailpro.\nCada email enviado consome um crédito. Os créditos não expiram com a subscrição,\nmas só podem ser utilizados enquanto a subscrição estiver ativa.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo de créditos devolvido com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Credits": 48500
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/account/subscriptionEndDate.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSubscriptionEndDate",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obter data de fim da subscrição",
        "description": "Devolve a data de expiração da subscrição Mailpro atual.\nApós a data de expiração, os envios são bloqueados até que a subscrição seja renovada.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Data de fim da subscrição devolvida com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "SubscriptionEndDate": "2027-01-15T00:00:00"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obter quota mensal da API",
        "description": "Devolve a quota mensal de pedidos à API do cliente autenticado.\n\n**Cálculo da quota:** o limite é calibrado a partir dos créditos\nde subscrição de email (normalmente `créditos_de_subscrição × 5`). Para\num plano de 10 000 emails por mês, isto resulta num orçamento mensal\nde 50 000 pedidos. Reinicia na **data de aniversário da subscrição** (não no\ndia 1 do mês de calendário).\n\n**O que consome créditos:**\n- Cada pedido autenticado à API para os endpoints `v2`, `v3` ou `sms`.\n- Cada evento de webhook enviado para um endpoint subscrito.\n\n**O que é GRATUITO (não consome créditos):**\n- Endpoints `/health`.\n- Pedidos que falhem com `401`, `403` ou `429`.\n- Eventos de webhook para clientes sem subscrição correspondente.\n\nA quota é **partilhada por todas as 3 APIs Mailpro** (`v2`, `v3`, `sms`)\n— um cliente = um orçamento mensal em toda a plataforma.\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": 0
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Nenhum registo de quota encontrado (conta recém-criada; a linha será criada no primeiro pedido autenticado)."
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listLists",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar todas as listas",
        "description": "Devolve todas as listas da conta, ordenadas por data de criação (mais recentes primeiro),\na menos que `sortByName=true` esteja definido.\nUtilize `type=0` para listas normais ou `type=1` para listas negras.\n\n> **Alias legado:** `/addressbook/list.{format}` — mesmo endpoint, mantido por compatibilidade\n> retroativa. As novas integrações devem utilizar `/list/*`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleFilter",
            "in": "query",
            "description": "Filtrar por título (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`0` = apenas listas padrão, `1` = apenas listas negras. Omitir para devolver todas.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Defina como `true` para ordenar os resultados alfabeticamente por título",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listas devolvidas com sucesso.\n\n> A resposta contém também um campo duplicado legado `AddressBookList` (conteúdo idêntico)\n> e cada item tem um `AddressBookID` duplicado legado (idêntico a `ListID`). As novas\n> integrações devem ignorá-los.\n",
            "content": {
              "application/json": {
                "example": {
                  "Lists": [
                    {
                      "ListID": 101,
                      "Title": "Newsletter — France",
                      "Type": 0,
                      "NumberEmails": 4521,
                      "CreationDate": "2025-01-15T10:30:00"
                    },
                    {
                      "ListID": 102,
                      "Title": "Unsubscribers",
                      "Type": 1,
                      "NumberEmails": 312,
                      "CreationDate": "2025-01-15T10:31:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Criar uma lista",
        "description": "Cria uma nova lista (lista de contactos).\nA lista começa vazia — adicione contactos com `/email/add` ou `/email/addSingle`.\n**Má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\n> **Alias legado:** `/addressbook/add.{format}` — mesmo endpoint, mantido por compatibilidade retroativa.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Title"
                ],
                "properties": {
                  "Title": {
                    "type": "string",
                    "description": "Nome visível da nova lista",
                    "example": "Spring Campaign 2026"
                  },
                  "Type": {
                    "type": "integer",
                    "description": "`0` = lista padrão (predefinido), `1` = lista negra",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista criada com sucesso.\n\n> Também é devolvido um campo duplicado legado `AddressBookList` (conteúdo idêntico).\n",
            "content": {
              "application/json": {
                "example": {
                  "Lists": [
                    {
                      "ListID": 103,
                      "Title": "Spring Campaign 2026",
                      "Type": 0,
                      "NumberEmails": 0,
                      "CreationDate": "2026-04-14T12:00:00"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Title em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "422": {
            "description": "Limite de listas (1000) atingido"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Renomear uma lista",
        "description": "Atualiza o título de uma lista existente.\nOs contactos dentro da lista não são afetados.\n\n> **Alias legado:** `/addressbook/edit.{format}` — mesmo endpoint, mantido por compatibilidade retroativa.\n> O nome de parâmetro `AddressBookID` também é aceite como alias legado de `ListID`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "ListID",
                  "Title"
                ],
                "properties": {
                  "ListID": {
                    "type": "integer",
                    "description": "ID da lista a renomear (a partir de `/list/list`). O alias legado `AddressBookID` também é aceite.",
                    "example": 101
                  },
                  "Title": {
                    "type": "string",
                    "description": "Novo título para a lista",
                    "example": "Newsletter — Europe"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista renomeada com sucesso"
          },
          "400": {
            "description": "ListID ou Title em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Lista não encontrada"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar uma lista",
        "description": "Elimina permanentemente uma lista **e todos os contactos que contém**.\nEsta ação não pode ser anulada.\n\n> **Alias legado:** `/addressbook/del.{format}` — mesmo endpoint, mantido por compatibilidade retroativa.\n> O nome de parâmetro `AddressBookID` também é aceite como alias legado de `ListID`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "ListID"
                ],
                "properties": {
                  "ListID": {
                    "type": "integer",
                    "description": "ID da lista a eliminar. O alias legado `AddressBookID` também é aceite.",
                    "example": 101
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista eliminada com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "ListID em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Lista não encontrada"
          }
        }
      }
    },
    "/email/list.{format}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "listEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar contactos",
        "description": "Devolve uma lista paginada de contactos de email da conta.\nFiltre por lista ou por padrão de email.\nOs resultados são ordenados alfabeticamente quando `sortByName=true`, caso contrário, por ordem de inserção.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtrar por endereço de email (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "name": "listId",
            "in": "query",
            "description": "Devolver apenas contactos nesta lista. O alias legado `addressBookId` também é aceite.",
            "schema": {
              "type": "integer"
            },
            "example": 101
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Defina como `true` para ordenar os resultados alfabeticamente por endereço de email",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de contactos devolvida com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Emails": [
                    {
                      "IdEmail": 10001,
                      "Email": "alice@example.com",
                      "Field1": "Alice",
                      "Field2": "Dupont"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/email/add.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Importar contactos (em massa)",
        "description": "Importa um ou mais endereços de email para uma lista num único pedido.\nIndique os endereços em `EmailList` separados por ponto e vírgula.\n\n**Exemplo:** `alice@example.com;bob@example.com;carol@example.com`\n\nEste endpoint só importa endereços de email. Para definir também valores de campos personalizados,\nutilize antes `/email/addSingle` para cada contacto.\n\nOs endereços previamente cancelados da subscrição são ignorados silenciosamente, a menos que `Force=1` seja definido.\n\n**Seleção da lista:** indique `ListId` (ou o seu alias legado `AddressBookId`). É obrigatório indicar pelo menos um.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailList"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "ID da lista de destino. O alias legado `AddressBookId` também é aceite.",
                    "example": 101
                  },
                  "EmailList": {
                    "type": "string",
                    "description": "Endereços de email a importar, separados por ponto e vírgula",
                    "example": "alice@example.com;bob@example.com;carol@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Defina como `1` para reimportar endereços que tinham cancelado anteriormente a subscrição.\nValor predefinido: `0` (os endereços com cancelamento são ignorados).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contactos importados com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "3 contacts imported"
                }
              }
            }
          },
          "400": {
            "description": "EmailList em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/email/addSingle.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addSingleEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Adicionar um único contacto",
        "description": "Adiciona um contacto a uma lista com valores opcionais para campos personalizados.\n\n`Field1` a `Field25` correspondem às definições de colunas personalizadas da sua lista.\nO mapeamento depende da ordem em que as colunas foram definidas — verifique as definições da lista\nna interface da Mailpro para ver que número de campo corresponde a cada coluna\n(por exemplo, Field1 = Nome, Field2 = Apelido, Field3 = Cidade…).\n\n**Seleção da lista:** indique `ListId` (ou o seu alias legado `AddressBookId`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "ID da lista de destino. O alias legado `AddressBookId` também é aceite.",
                    "example": 101
                  },
                  "Email": {
                    "type": "string",
                    "description": "Endereço de email do novo contacto",
                    "example": "alice@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Defina como `1` para voltar a adicionar um endereço que tinha cancelado anteriormente a subscrição",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Valor para o campo personalizado 1 (o mapeamento das colunas depende da sua lista)",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Valor para o campo personalizado 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Valor para o campo personalizado 3",
                    "example": "Paris"
                  },
                  "Field4": {
                    "type": "string",
                    "description": "Valor para o campo personalizado 4"
                  },
                  "Field5": {
                    "type": "string",
                    "description": "Valor para o campo personalizado 5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacto adicionado com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "EmailId": 10002,
                  "Email": "alice@example.com",
                  "Field1": "Alice",
                  "Field2": "Dupont",
                  "ListID": 101
                }
              }
            }
          },
          "400": {
            "description": "Email em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/email/edit.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "editEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Atualizar um contacto",
        "description": "Atualiza o endereço de email e/ou os valores dos campos personalizados de um contacto existente.\nIdentifique o contacto pelo `EmailId` (a partir de `/email/list`).\nTanto `EmailId` como `Email` são obrigatórios.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailId",
                  "Email"
                ],
                "properties": {
                  "EmailId": {
                    "type": "integer",
                    "description": "ID do contacto a atualizar (a partir de `/email/list`)",
                    "example": 10001
                  },
                  "Email": {
                    "type": "string",
                    "description": "Novo endereço de email do contacto",
                    "example": "alice.updated@example.com"
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Novo valor para o campo personalizado 1",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Novo valor para o campo personalizado 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Novo valor para o campo personalizado 3"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacto atualizado com sucesso"
          },
          "400": {
            "description": "EmailId ou Email em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Contacto não encontrado"
          }
        }
      }
    },
    "/email/del.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "deleteEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar um contacto",
        "description": "Elimina permanentemente um contacto pelo seu identificador único.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailId"
                ],
                "properties": {
                  "EmailId": {
                    "type": "integer",
                    "description": "ID do contacto a eliminar (a partir de `/email/list`)",
                    "example": 10001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacto eliminado com sucesso"
          },
          "400": {
            "description": "EmailId em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Contacto não encontrado"
          }
        }
      }
    },
    "/message/list.{format}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar modelos de mensagem",
        "description": "Devolve os modelos de email HTML guardados para a conta.\nPor predefinição, o corpo HTML **não** é incluído na resposta para manter os payloads pequenos.\nDefina `bodyHTML=true` para o incluir (limita automaticamente os resultados a 10 por página).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectFilter",
            "in": "query",
            "description": "Filtrar por assunto (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Defina como `true` para incluir o corpo HTML completo em cada resultado.\nQuando definido como `true`, os resultados são automaticamente limitados a 10 por página, independentemente do `numberOfRecords`.\n",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Modelos de mensagem devolvidos com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "MessageList": [
                    {
                      "IDMessage": 501,
                      "Subject": "Spring Newsletter — April 2026",
                      "Language": "EN",
                      "LinkAlign": "center",
                      "LinkUp": 0,
                      "UpdateDate": "2026-03-10T14:22:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/message/add.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "addMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Criar um modelo de mensagem",
        "description": "Cria um novo modelo de email HTML.\nO modelo armazena o assunto, o corpo HTML e as definições da hiperligação de cancelamento de subscrição.\nUma vez criado, utilize o `IDMessage` devolvido ao lançar uma campanha.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Subject",
                  "BodyHTML",
                  "Language",
                  "LinkAlign",
                  "LinkUp"
                ],
                "properties": {
                  "Subject": {
                    "type": "string",
                    "description": "Linha de assunto do email (máx. 255 caracteres)",
                    "example": "Spring Newsletter — April 2026"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Conteúdo HTML completo do corpo do email",
                    "example": "<h1>Spring is here!</h1><p>Check out our latest offers.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Código de idioma para a localização da hiperligação de cancelamento de subscrição (por exemplo, `EN`, `FR`, `DE`)",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "description": "Alinhamento horizontal da hiperligação de cancelamento de subscrição",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "description": "Posição da hiperligação de cancelamento de subscrição — `0` = parte inferior do email, `1` = parte superior",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modelo de mensagem criado com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "IDMessage": 502,
                  "Subject": "Spring Newsletter — April 2026",
                  "Language": "EN",
                  "LinkAlign": "center",
                  "LinkUp": 0
                }
              }
            }
          },
          "400": {
            "description": "Campo obrigatório em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/message/edit.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "editMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Atualizar um modelo de mensagem",
        "description": "Atualiza o conteúdo e os metadados de um modelo de mensagem existente.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId",
                  "Subject",
                  "BodyHTML",
                  "Language",
                  "LinkAlign",
                  "LinkUp"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "ID do modelo de mensagem a atualizar (a partir de `/message/list`)",
                    "example": 501
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Nova linha de assunto do email",
                    "example": "Spring Newsletter — April 2026 (revised)"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Novo conteúdo HTML do corpo do email",
                    "example": "<h1>Spring is here!</h1><p>Updated content.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Código de idioma para a localização da hiperligação de cancelamento de subscrição",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modelo de mensagem atualizado com sucesso"
          },
          "400": {
            "description": "Campo obrigatório em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Modelo de mensagem não encontrado"
          }
        }
      }
    },
    "/message/del.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "deleteMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar um modelo de mensagem",
        "description": "Elimina permanentemente um modelo de mensagem pelo seu identificador único.\nOs modelos utilizados por campanhas agendadas pendentes não podem ser eliminados.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "ID do modelo de mensagem a eliminar (a partir de `/message/list`)",
                    "example": 501
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modelo de mensagem eliminado com sucesso"
          },
          "400": {
            "description": "MessageId em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Modelo de mensagem não encontrado"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar campanhas agendadas",
        "description": "Devolve a lista das campanhas de email agendadas e recentemente processadas.\nOs resultados são ordenados por data de envio prevista (mais recentes primeiro).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtrar por assunto da campanha (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de campanhas devolvida com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "sends": [
                    {
                      "IDSend": 3001,
                      "ListID": 101,
                      "SenderEmail": "newsletter@yourcompany.com",
                      "SenderName": "Your Company Newsletter",
                      "DatePlanned": "2026-04-20T09:00:00",
                      "SubjectMessage": "Spring Newsletter — April 2026",
                      "NumberCredit": 4521
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/campaign.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lançar uma campanha",
        "description": "Agenda ou envia imediatamente uma campanha de email para uma lista\nutilizando um modelo de mensagem guardado e um endereço de remetente.\n\n**Obrigatórios:**\n- `IDMessage` — o modelo a enviar (a partir de `/message/list`)\n- `IDEmailExp` — o endereço de remetente a utilizar (a partir de `/senderEmail/list`)\n- `ListId` — a lista de destinatários (a partir de `/list/list`). O alias legado `IDAddressBook` também é aceite.\n\n**Agendamento:** defina `DatePlanned` para uma data/hora ISO 8601 futura para agendar o envio.\nOmita `DatePlanned` para enviar imediatamente.\n\n**Acompanhamento de estatísticas:** defina `Campaign=1` e indique um `TitleCampaign` para ativar\no acompanhamento de aberturas/cliques/devoluções na secção de Estatísticas.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDMessage",
                  "IDEmailExp"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "ID da lista de destinatários (a partir de `/list/list`). O alias legado `IDAddressBook` também é aceite.",
                    "example": 101
                  },
                  "IDMessage": {
                    "type": "integer",
                    "description": "ID do modelo de mensagem a enviar (a partir de `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID do endereço de email do remetente a utilizar (a partir de `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDUnsubscribeList": {
                    "type": "integer",
                    "description": "Lista utilizada para recolher contactos com subscrição cancelada (lista negra).\nO alias legado `IDUnsubscribeAddressBook` também é aceite.\n",
                    "example": 102
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Data/hora de envio agendadas (ISO 8601). Omita para enviar imediatamente.",
                    "example": "2026-04-20T09:00:00"
                  },
                  "Campaign": {
                    "type": "integer",
                    "description": "Defina como `1` para acompanhar este envio como uma campanha identificada nas estatísticas",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 1
                  },
                  "TitleCampaign": {
                    "type": "string",
                    "description": "Título da campanha apresentado nas estatísticas (obrigatório quando `Campaign=1`)",
                    "example": "Spring Newsletter April 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campanha agendada ou enviada com sucesso.\n\n> A resposta devolve também os aliases legados `AddressBookID` e `UnsubscribeAddressBookID`\n> (idênticos a `ListID` / `UnsubscribeListID`). As novas integrações devem ignorá-los.\n",
            "content": {
              "application/json": {
                "example": {
                  "send": {
                    "IDSend": 3002,
                    "ListID": 101,
                    "UnsubscribeListID": 102,
                    "IDCampaign": 8001,
                    "SenderName": "Your Company Newsletter",
                    "SenderEmail": "newsletter@yourcompany.com",
                    "DatePlanned": "2026-04-20T09:00:00",
                    "SubjectMessage": "Spring Newsletter — April 2026",
                    "NumberCredit": 4521
                  }
                }
              }
            }
          },
          "400": {
            "description": "IDMessage ou IDEmailExp em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "403": {
            "description": "Créditos de email insuficientes"
          },
          "404": {
            "description": "Lista, mensagem ou remetente não encontrados"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "deleteCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar ou eliminar uma campanha",
        "description": "Cancela um envio de campanha **agendado e pendente**, ou elimina um envio já **concluído**.\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": [
                  "IdSend"
                ],
                "properties": {
                  "IdSend": {
                    "type": "integer",
                    "description": "ID do envio de campanha a cancelar ou eliminar (a partir de `/send/list`)",
                    "example": 3001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campanha cancelada ou eliminada com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Campaign Deleted"
                }
              }
            }
          },
          "400": {
            "description": "IdSend em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Campanha não encontrada"
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listScheduledCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar as minhas campanhas de email agendadas",
        "description": "Devolve as campanhas de email e os envios únicos agendados para uma data futura que\nainda não foram despachados. Útil antes de chamar `/cancel` ou `/reschedule`.\nOs registos são ordenados por `DatePlanned` ascendente.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de campanhas / envios agendados.\n\n> Cada registo inclui também os aliases legados `AddressBookID` e\n> `UnsubscribeAddressBookID` (idênticos a `ListID` / `UnsubscribeListID`).\n",
            "content": {
              "application/json": {
                "example": {
                  "sends": [
                    {
                      "IDSend": 5001,
                      "ListID": 101,
                      "UnsubscribeListID": 102,
                      "IDCampaign": 8001,
                      "SenderName": "Your Company Newsletter",
                      "SenderEmail": "newsletter@yourcompany.com",
                      "DatePlanned": "2026-05-01T09:00:00",
                      "SubjectMessage": "Spring Sale 2026",
                      "NumberCredit": 4521
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/{IdSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "cancelScheduledCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar uma campanha / envio agendado",
        "description": "Cancela um envio de email agendado (campanha ou único) que ainda não foi despachado.\nSe o envio já tiver sido feito (ou não existir / pertencer a outro cliente),\ndevolve **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Envio cancelado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 5001
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "409": {
            "description": "Já despachado ou não encontrado"
          }
        }
      }
    },
    "/send/{IdSend}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "rescheduleCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reagendar uma campanha / envio agendado",
        "description": "Atualiza o `DatePlanned` de um envio de email agendado. A nova data tem de ser\n**futura** e **dentro de 90 dias**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "PlanDate"
                ],
                "properties": {
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "example": "2026-12-31T14:30:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envio reagendado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSend": 5001,
                  "NewPlanDate": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "PlanDate em falta ou inválido"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "409": {
            "description": "Já despachado, não encontrado, ou nova data fora do intervalo (tem de ser futura e dentro de 90 dias)"
          }
        }
      }
    },
    "/send/mail/scheduled.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "listScheduledMails",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar os emails individuais agendados",
        "description": "Devolve os emails individuais enviados com `/send/sendmail` e uma data futura, ainda não expedidos. As campanhas são listadas por `/send/scheduled`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Emails agendados devolvidos",
            "content": {
              "application/json": {
                "example": {
                  "scheduledMails": [
                    {
                      "IdSingleSend": 880123,
                      "Email": "jane@example.com",
                      "Subject": "Your invoice",
                      "DatePlanned": "2026-12-01T09:00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "cancelMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar um email individual agendado",
        "description": "Cancela o email enquanto não tiver sido expedido.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` devolvido por `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email cancelado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 880123
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "409": {
            "description": "Envio não encontrado ou já expedido"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/reschedule.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "rescheduleMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reagendar um email individual agendado",
        "description": "Altera a data de envio. A nova data tem de ser futura e dentro de 90 dias. `PATCH` também é aceite.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` devolvido por `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "PlanDate"
                ],
                "properties": {
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Nova data de envio (ISO 8601)",
                    "example": "2026-12-15T09:00:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email reagendado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSingleSend": 880123,
                  "NewPlanDate": "2026-12-15T09:00:00"
                }
              }
            }
          },
          "400": {
            "description": "Data em falta ou inválida"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "409": {
            "description": "Envio não encontrado, já expedido ou data fora dos limites"
          }
        }
      }
    },
    "/send/sendingTest.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendTestEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar um email de teste",
        "description": "Envia uma pré-visualização de um modelo de mensagem para um destinatário especificado para revisão\nantes de lançar a campanha real.\nO remetente, o modelo e o destinatário de teste são todos identificados pelos seus IDs.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId",
                  "IDEmailExpFrom",
                  "IDEmailExpTo"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "ID do modelo de mensagem a pré-visualizar (a partir de `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExpFrom": {
                    "type": "integer",
                    "description": "ID do endereço de remetente a utilizar (a partir de `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDEmailExpTo": {
                    "type": "integer",
                    "description": "ID do endereço de remetente destinatário — o email de teste é enviado para este endereço",
                    "example": 202
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email de teste enviado com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "SendingTest": {
                    "IdSendingTest": 7001,
                    "ToEmail": "test@yourcompany.com",
                    "FromEmail": "newsletter@yourcompany.com",
                    "SenderName": "Your Company Newsletter"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Campo obrigatório em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/send/sendmail.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "sendTransactionalEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar um email transacional",
        "description": "Envia um email transacional avulso para um ou mais destinatários.\nAo contrário das campanhas, este endpoint não exige uma lista —\no endereço do destinatário e o corpo HTML são indicados diretamente.\n\n**Obrigatórios:**\n- `IDEmailExp` — o ID do endereço de remetente (a partir de `/senderEmail/list`)\n- `EmailData` — destinatário no formato `email,field1,field2,...,field25` (separado por vírgulas)\n- `BodyHTML` — o corpo HTML\n- `Subject` — a linha de assunto\n\n**Formato de EmailData:** `alice@example.com,Alice,Dupont,Paris`\nO primeiro valor é o endereço de email; os valores 2 a 26 correspondem a Field1 a Field25 para\nas variáveis de personalização no seu modelo HTML.\n\n**Vários destinatários:** separe várias entradas `EmailData` com ponto e vírgula:\n`alice@example.com,Alice;bob@example.com,Bob`\n\n**Agendamento:** defina `DatePlanned` para uma data/hora ISO 8601 futura ou omita para enviar imediatamente.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID do endereço de email do remetente a utilizar (a partir de `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinatário no formato `email,campo1,campo2,...,campo25` (separados por vírgula).\nO primeiro valor é o endereço de email; os restantes são campos de personalização\nmapeados para Field1–Field25 no seu modelo HTML.\n\n**A parte local** do email (antes do `@`) aceita letras, dígitos e\n`. _ - +` — incluindo o sub-addressing RFC 5322 (`user+tag@domain`, ex. Gmail,\nFastmail, Proton). Os outros caracteres especiais permitidos pela RFC 5322\n(ex. `! # $ % & ' * / = ? ^ { | } ~`) e as partes locais entre aspas **não**\nsão aceites.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Conteúdo HTML completo do corpo do email",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Linha de assunto do email (máx. 255 caracteres)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "array",
                    "maxItems": 5,
                    "description": "Anexos opcionais — envie a requisição como `multipart/form-data` e adicione uma parte de arquivo por anexo (qualquer nome de campo). Até **5 arquivos**, **10 MB por arquivo**, **15 MB no total**. Tipos aceitos: PDF, Word, Excel, PowerPoint, imagens (JPG, PNG, GIF, WebP), ZIP, CSV, TXT — arquivos executáveis e scripts são rejeitados. **Cobrança:** o envio mantém seu crédito habitual, mais **1 crédito por 512 KB de anexos além dos primeiros 512 KB** (anexos ≤ 512 KB não adicionam nada). Todos os outros campos deste endpoint (`ReplyTo`, `ActivateStatistics`, `CustomHeaders`, …) funcionam exatamente como na variante form-urlencoded.",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (predefinição): os anexos são usados apenas para este envio — são guardados fora da sua\nconta, não contam para a sua quota de armazenamento e são eliminados automaticamente após\n35 dias. `true`: os anexos também são guardados nos ficheiros da sua conta (pasta\n`Secure/Files/Sending/api`) e contam para a sua quota de armazenamento.\n",
                    "example": false
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID do endereço de email do remetente a utilizar (a partir de `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinatário no formato `email,campo1,campo2,...,campo25` (separados por vírgula).\nO primeiro valor é o endereço de email; os restantes são campos de personalização\nmapeados para Field1–Field25 no seu modelo HTML.\n\n**A parte local** do email (antes do `@`) aceita letras, dígitos e\n`. _ - +` — incluindo o sub-addressing RFC 5322 (`user+tag@domain`, ex. Gmail,\nFastmail, Proton). Os outros caracteres especiais permitidos pela RFC 5322\n(ex. `! # $ % & ' * / = ? ^ { | } ~`) e as partes locais entre aspas **não**\nsão aceites.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Conteúdo HTML completo do corpo do email",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Linha de assunto do email (máx. 255 caracteres)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "string",
                    "description": "Anexos de ficheiro opcionais como um **array JSON** de objetos `{ \"filename\": …, \"content\": … }`, com `content` **codificado em Base64** (mesmo formato da API CRM v3). Até **5 ficheiros**, **10 MB por ficheiro** e **15 MB no total** (após a descodificação). São aceites os formatos comuns de documentos e imagens; os ficheiros executáveis e scripts são rejeitados. **Faturação:** o envio mantém o seu 1 crédito habitual, mais **1 crédito por 512 KB de anexos além dos primeiros 512 KB**. *Em alternativa, pode enviar os ficheiros como partes `multipart/form-data` (ver o corpo do pedido multipart acima) — ambos funcionam.*",
                    "example": "[{\"filename\":\"invoice.pdf\",\"content\":\"JVBERi0xLjQK...\"}]"
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (predefinição): os anexos são usados apenas para este envio — são guardados fora da sua\nconta, não contam para a sua quota de armazenamento e são eliminados automaticamente após\n35 dias. `true`: os anexos também são guardados nos ficheiros da sua conta (pasta\n`Secure/Files/Sending/api`) e contam para a sua quota de armazenamento.\n",
                    "example": false
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Data/hora de envio agendadas (ISO 8601). Omita para enviar imediatamente.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "ActivateStatistics": {
                    "type": "boolean",
                    "description": "Defina como `true` para acompanhar aberturas e cliques deste email",
                    "default": false,
                    "example": true
                  },
                  "ReplyTo": {
                    "type": "string",
                    "description": "Endereço de email para resposta. Se omitido, as respostas vão para o endereço do remetente.",
                    "example": "support@yourcompany.com"
                  },
                  "UnsubscriptionLink": {
                    "type": "boolean",
                    "description": "Defina como `true` para acrescentar uma hiperligação de cancelamento de subscrição ao corpo do email",
                    "default": false,
                    "example": false
                  },
                  "CustomHeaders": {
                    "type": "string",
                    "description": "Cabeçalhos SMTP adicionais como uma string `chave=valor` separada por ponto e vírgula",
                    "example": "X-Campaign-ID=campaign_42;X-Priority=1"
                  },
                  "BodyText": {
                    "type": "string",
                    "description": "Versão alternativa em texto simples para clientes de email que não renderizam HTML",
                    "example": "Hello Alice, your order has been confirmed."
                  },
                  "List_Unsubscribe": {
                    "type": "string",
                    "description": "Valor para o cabeçalho de email `List-Unsubscribe` (URL ou mailto)",
                    "example": "https://yourcompany.com/unsubscribe?token=abc123"
                  },
                  "List_Unsubscribe_Post": {
                    "type": "string",
                    "description": "Valor para o cabeçalho `List-Unsubscribe-Post` (RFC 8058)",
                    "example": "List-Unsubscribe=One-Click"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email transacional enviado ou agendado com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "SingleSend": {
                    "IdSingleSend": 8001,
                    "IdEmailExp": 201,
                    "DatePlanned": "2026-04-15T14:30:00",
                    "Subject": "Your order #12345 is confirmed",
                    "Email": "alice@example.com",
                    "Field1": "Alice",
                    "Field2": "Dupont",
                    "UnsubscriptionLink": false,
                    "ActivateStatistics": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Campo obrigatório em falta ou formato de email inválido"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "403": {
            "description": "Créditos de email insuficientes"
          },
          "404": {
            "description": "Remetente não encontrado ou endereço de email com subscrição cancelada"
          }
        }
      }
    },
    "/send/{IdSend}/status.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "getTransactionalStatus",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obter o estado de entrega de um e-mail transacional",
        "description": "Devolve o estado de entrega atual de um e-mail transacional enviado com `/send/sendmail`. Passe o `IdSingleSend` que essa chamada devolveu.\n\nValores possíveis: `delivered` (aceite pelo servidor do destinatário, ver `DiagCode`), `bounced` (recusado — `BounceType: hard` endereço inválido ou recusa definitiva, `soft` recusa após novas tentativas), `sent` (entregue ao servidor de correio, ainda sem resposta), `scheduled` (ainda não enviado, `DatePlanned` no futuro) e `queued` (à espera de envio). `delivered` e `bounced` são finais: pare de consultar. Cada email tem um estado final no máximo 48 horas após o envio; consulte no máximo a cada 15 minutos (cada chamada conta para a sua quota da API) ou utilize os webhooks `email.delivered` / `email.bounced`. Só o cliente que enviou o email pode ler o seu estado — qualquer outro id devolve 404.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "description": "O `IdSingleSend` retornado por `/send/sendmail`.",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Estado de entrega atual",
            "content": {
              "application/json": {
                "example": {
                  "status": {
                    "IdSingleSend": 8001,
                    "Email": "alice@example.com",
                    "Status": "delivered",
                    "DatePlanned": "2026-04-15T14:30:00",
                    "StatusDate": "2026-04-15T14:30:07",
                    "DiagCode": "2.0.0 (success)",
                    "BounceType": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Nenhum envio transacional encontrado com este id para este cliente"
          }
        }
      }
    },
    "/senderEmail/list.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "listSenderEmails",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar endereços de remetente validados",
        "description": "Devolve a lista dos endereços de email de remetente configurados para a conta.\nApenas os endereços com `IsValid: true` podem ser utilizados ao enviar campanhas.\nOs novos endereços são adicionados com `/senderEmail/add` e tornam-se válidos depois de clicar na hiperligação do email de validação.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtrar por endereço de email (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "@yourcompany.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Defina como `true` para ordenar os resultados alfabeticamente pelo nome do remetente",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endereços de remetente devolvidos com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "ExpEmailList": [
                    {
                      "IDEmailExp": 201,
                      "Email": "newsletter@yourcompany.com",
                      "SenderName": "Your Company Newsletter",
                      "IsValid": true,
                      "CreationDate": "2025-06-01T09:00:00"
                    },
                    {
                      "IDEmailExp": 202,
                      "Email": "support@yourcompany.com",
                      "SenderName": "Your Company Support",
                      "IsValid": true,
                      "CreationDate": "2025-06-01T09:05:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/senderEmail/add.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "addSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Adicionar um endereço de remetente",
        "description": "Adiciona o endereço com os mesmos controlos da aplicação e envia-lhe um email de validação. Pode ser utilizado depois de clicar na hiperligação desse email. Uma conta pode ter até 25 remetentes, validados ou pendentes.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email",
                  "SenderName"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Endereço do remetente",
                    "example": "news@example.com"
                  },
                  "SenderName": {
                    "type": "string",
                    "description": "Nome apresentado aos destinatários",
                    "example": "Example News"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Endereço adicionado. `DomainHasMx` é false quando o domínio não tem registo MX.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true,
                  "DomainHasMx": true
                }
              }
            }
          },
          "400": {
            "description": "`Email` ou `SenderName` em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "422": {
            "description": "Endereço recusado: inválido, já entre os remetentes da conta, domínio de email público, nome proibido ou limite de 25 atingido. A mensagem indica o motivo."
          },
          "503": {
            "description": "Temporariamente indisponível, tente novamente"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/resendValidation.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "resendSenderValidation",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar novamente o email de validação",
        "description": "Para um endereço ainda a aguardar validação.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID do remetente, de `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email enviado novamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Remetente não encontrado"
          },
          "409": {
            "description": "Este remetente já está validado"
          },
          "503": {
            "description": "Temporariamente indisponível, tente novamente"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/authentication.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "getSenderAuthentication",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Verificar o domínio de um remetente (SPF, DKIM, DMARC, MX)",
        "description": "Verifica o domínio em direto no DNS e devolve os registos a publicar. Apenas leitura. O DKIM é ativado na aplicação: `DkimSettingsUrl` abre o ecrã certo.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID do remetente, de `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Estado do domínio. `Spf.RecommendedRecord` é criado a partir do seu registo atual: publique-o apenas se `Spf.ChangeNeeded` for true.",
            "content": {
              "application/json": {
                "example": {
                  "Domain": "example.com",
                  "Spf": {
                    "Valid": true,
                    "Record": "v=spf1 include:spf.mailpro.com -all",
                    "RecommendedRecord": "v=spf1 include:spf.mailpro.com -all",
                    "ChangeNeeded": false
                  },
                  "Dkim": {
                    "Valid": true,
                    "Records": [
                      {
                        "Host": "key._domainkey.example.com",
                        "Value": "v=DKIM1;k=rsa;p=MIIBIjANBgkq...",
                        "Validated": true
                      }
                    ]
                  },
                  "Dmarc": {
                    "Valid": true,
                    "Record": "v=DMARC1; p=quarantine"
                  },
                  "Mx": {
                    "Valid": true,
                    "Record": "mail.example.com"
                  },
                  "DkimSettingsUrl": "https://app.mailpro.com/dkim/list?d=example.com"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Remetente não encontrado"
          },
          "503": {
            "description": "Temporariamente indisponível, tente novamente"
          }
        }
      }
    },
    "/senderEmail/del.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "deleteSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remover um endereço de remetente",
        "description": "Remove um endereço de email de remetente validado da conta.\nOs endereços de remetente utilizados por campanhas agendadas não podem ser eliminados.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "idEmailExp"
                ],
                "properties": {
                  "idEmailExp": {
                    "type": "integer",
                    "description": "ID do endereço de remetente a remover (a partir de `/senderEmail/list`)",
                    "example": 201
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Endereço de remetente removido com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "EmailSender Deleted"
                }
              }
            }
          },
          "400": {
            "description": "idEmailExp em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/list.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "listStats",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar estatísticas de campanha",
        "description": "Devolve métricas globais de desempenho de todas as campanhas: número enviado, taxa de abertura,\ntaxa de cliques, número de devoluções. Filtre por intervalo de datas ou título de campanha.\nOs resultados são ordenados por data de envio (mais recente primeiro).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleCampaignFilter",
            "in": "query",
            "description": "Filtrar por título da campanha (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "spring"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "dateStart",
            "in": "query",
            "description": "Início do filtro de intervalo de datas (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-01-01T00:00:00"
          },
          {
            "name": "dateEnd",
            "in": "query",
            "description": "Fim do filtro de intervalo de datas (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-12-31T23:59:59"
          }
        ],
        "responses": {
          "200": {
            "description": "Estatísticas de campanha devolvidas com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Campaigns": [
                    {
                      "IdCampaign": 8001,
                      "DateCampaign": "2026-04-20T09:00:01",
                      "TitleCampaign": "Spring Newsletter April 2026",
                      "NumberEmailSend": 4521,
                      "NumberEmailOpen": 1823,
                      "NumberEmailClick": 342,
                      "BadMail": 12,
                      "NumberUnsubscribers": 8,
                      "NumberComplaints": 1,
                      "SpamTrap": 0,
                      "DeliverabilityScore": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/byHour.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByHour",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Estatísticas por hora",
        "description": "Devolve a decomposição horária de aberturas e cliques de uma campanha específica.\nÚtil para compreender o melhor horário de envio.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID da campanha (a partir de `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Estatísticas horárias devolvidas com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "ByHour": [
                    {
                      "Hour": 9,
                      "Opens": 823,
                      "Clicks": 142
                    },
                    {
                      "Hour": 10,
                      "Opens": 512,
                      "Clicks": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/byDay.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByDay",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Estatísticas por dia",
        "description": "Devolve a decomposição diária de aberturas e cliques de uma campanha específica.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID da campanha (a partir de `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Estatísticas diárias devolvidas com sucesso"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/del.{format}": {
      "post": {
        "tags": [
          "Statistics"
        ],
        "operationId": "deleteStats",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar estatísticas de campanha",
        "description": "Elimina permanentemente todos os registos de estatísticas de uma determinada campanha.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IdCampaign"
                ],
                "properties": {
                  "IdCampaign": {
                    "type": "integer",
                    "description": "ID da campanha cujas estatísticas eliminar (a partir de `/stats/list`)",
                    "example": 8001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estatísticas de campanha eliminadas com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Statistic Deleted"
                }
              }
            }
          },
          "400": {
            "description": "IdCampaign em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Campanha não encontrada"
          }
        }
      }
    },
    "/stats/country.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsCountry",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Decomposição por geolocalização",
        "description": "Devolve a decomposição por geolocalização das aberturas de campanha — quantas aberturas vieram\nde cada país.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Decomposição por país devolvida"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/open.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsOpens",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registo de eventos de abertura",
        "description": "Devolve o registo, por destinatário, dos eventos de abertura de uma campanha (uma linha por abertura).\nUtilize `emailFilter` para procurar um destinatário específico (correspondência parcial, sem distinção entre maiúsculas e minúsculas).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "name": "emailFilter",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Eventos de abertura devolvidos"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/click.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsClicks",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registo de eventos de clique",
        "description": "Devolve o registo, por destinatário, dos eventos de clique de uma campanha — incluindo\nque hiperligação foi clicada e quando.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "name": "emailFilter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Eventos de clique devolvidos"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/system.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsSystem",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Decomposição por sistema operativo",
        "description": "Devolve a decomposição das aberturas por sistema operativo (Windows, macOS, iOS,\nAndroid, Linux, etc.) de uma determinada campanha.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Decomposição por SO devolvida"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/emailSoftware.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsEmailSoftware",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Decomposição por cliente de email",
        "description": "Devolve a decomposição das aberturas por cliente de email (Gmail, Outlook, Apple Mail,\nThunderbird, etc.) de uma determinada campanha.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Decomposição por cliente de email devolvida"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/stats/bounce.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsBounce",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registo de devoluções",
        "description": "Devolve a lista de destinatários devolvidos (devoluções definitivas, devoluções temporárias,\nqueixas de spam) de uma campanha, com o motivo da falha para cada endereço.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "name": "emailFilter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Eventos de devolução devolvidos",
            "content": {
              "application/json": {
                "example": {
                  "ListBadMail": [
                    {
                      "Email": "bounce@example.com",
                      "Date": "2026-04-20T09:05:12",
                      "Error": "550 5.1.1 recipient rejected",
                      "AddressbookId": 1813318
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/suppression/bounces.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listBounces",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar os bounces da conta",
        "description": "Os mais recentes primeiro. O total está no cabeçalho `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`hard` ou `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origem do bounce: `list`, `contact`, `api` ou `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Endereço exato",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "A partir desta data",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Até esta data",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bounces devolvidos",
            "content": {
              "application/json": {
                "example": {
                  "bounces": [
                    {
                      "Id": 5521,
                      "Source": "contact",
                      "BounceType": "hard",
                      "Email": "old@example.com",
                      "Date": "2026-10-12T08:30:00",
                      "DiagCode": "550 5.1.1 User unknown",
                      "IdList": 101
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`type` tem de ser `hard` ou `soft`"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remover um bounce",
        "description": "`Source` e `Type` são obrigatórios, tal como devolvidos por `/suppression/bounces`: um `Id` sozinho não é único.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` do bounce",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Source",
                  "Type"
                ],
                "properties": {
                  "Source": {
                    "type": "string",
                    "description": "`list`, `contact`, `api` ou `smtp`"
                  },
                  "Type": {
                    "type": "string",
                    "enum": [
                      "hard",
                      "soft"
                    ],
                    "description": "`hard` ou `soft`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bounce removido",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": false
                }
              }
            }
          },
          "400": {
            "description": "`Source` ou `Type` em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Bounce não encontrado"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/restore.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "restoreBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Repor nas suas listas um contacto com hard bounce",
        "description": "Apenas para um hard bounce com a origem `contact`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` do bounce",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contacto reposto",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": true
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Hard bounce de um contacto não encontrado ou endereço já não ativo"
          }
        }
      }
    },
    "/suppression/unsubscribers.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar os cancelamentos de subscrição da conta",
        "description": "Os mais recentes primeiro. O total está no cabeçalho `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origem do cancelamento: `contact`, `list`, `smtp`, `api` ou `api3`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Endereço exato",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "A partir desta data",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Até esta data",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelamentos de subscrição devolvidos",
            "content": {
              "application/json": {
                "example": {
                  "unsubscribers": [
                    {
                      "Id": 9012,
                      "Source": "api",
                      "Email": "stop@example.com",
                      "Date": "2026-10-20T16:05:00",
                      "ListName": null,
                      "Comment": "Asked by phone"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/suppression/unsubscribers/add.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "addUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Adicionar um cancelamento de subscrição",
        "description": "Sem `ListId`, a subscrição do endereço é cancelada para toda a conta. Com `ListId`, apenas nessa lista de cancelamento.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Endereço cuja subscrição cancelar",
                    "example": "stop@example.com"
                  },
                  "Comment": {
                    "type": "string",
                    "description": "Comentário livre",
                    "example": "Asked by phone"
                  },
                  "ListId": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Lista de cancelamento da conta (opcional)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Concluído. `AlreadyUnsubscribed` é true quando a subscrição do endereço já estava cancelada.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "AlreadyUnsubscribed": false
                }
              }
            }
          },
          "400": {
            "description": "É necessário um endereço válido"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "`ListId` não é uma lista de cancelamento desta conta"
          }
        }
      }
    },
    "/suppression/unsubscribers/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Remover um cancelamento de subscrição",
        "description": "`Source` é obrigatório, tal como devolvido por `/suppression/unsubscribers`: um `Id` sozinho não é único.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` do cancelamento",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Source"
                ],
                "properties": {
                  "Source": {
                    "type": "string",
                    "description": "`contact`, `list`, `smtp`, `api` ou `api3`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancelamento de subscrição removido",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Removed": 9012
                }
              }
            }
          },
          "400": {
            "description": "`Source` é obrigatório"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "404": {
            "description": "Cancelamento de subscrição não encontrado"
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listHistory",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar histórico de envios",
        "description": "Devolve um registo paginado de todos os envios de email passados.\nFiltre por ID de campanha ou por assunto.\nDefina `bodyHTML=true` para incluir o corpo HTML (limita automaticamente a 10 por página).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtrar por assunto da campanha (correspondência parcial, sem distinção entre maiúsculas e minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "description": "Devolver o histórico apenas de uma campanha específica",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Defina como `true` para incluir o corpo HTML completo.\nLimita automaticamente os resultados a 10 por página.\n",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Histórico devolvido com sucesso",
            "content": {
              "application/json": {
                "example": {
                  "HistoricList": [
                    {
                      "IDHistoric": 9001,
                      "SubjectMessage": "Spring Newsletter — April 2026",
                      "DateSend": "2026-04-20T09:00:01",
                      "NumberSend": 4521,
                      "NumberOpen": 1823,
                      "NumberClick": 342
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Carregar um ficheiro de contactos (CSV / XLSX) para importação em massa",
        "description": "Carregue um ficheiro CSV ou XLSX para importar contactos de email para uma lista.\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- `IdClient` (inteiro) — o seu ID de cliente Mailpro\n- `ApiKey` (string) — a sua chave de API\n- `ListId` (inteiro) — ID da lista de destino. O alias legado `AddressBookId` também é aceite.\n- `file` (binário) — o ficheiro CSV ou XLSX a carregar\n\n**Opcional:**\n- `WebhookUrl` (string) — URL HTTPS chamado quando o processamento terminar.\n  Recebe um payload JSON com o estado final (success / failed) e\n  contagens de linhas importadas / ignoradas / inválidas.\n\n**Formato do ficheiro:**\n- Codificação UTF-8\n- Primeira linha = cabeçalhos (um tem de ser `Email` — sem distinção entre maiúsculas e minúsculas)\n- As outras colunas correspondem a campos personalizados da lista de destino\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": [
                  "ListId",
                  "file"
                ],
                "properties": {
                  "ListId": {
                    "type": "integer",
                    "description": "ID da lista de destino. O alias legado `AddressBookId` também é aceite.",
                    "example": 101
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Ficheiro CSV ou XLSX (UTF-8, máx. 50 MB)"
                  },
                  "WebhookUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL de callback invocado quando o processamento terminar",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ficheiro aceite e colocado em fila",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 13,
                  "InternalName": "230575-20260420140221-contacts.csv"
                }
              }
            }
          },
          "400": {
            "description": "Nenhum ficheiro carregado ou ListId em falta"
          },
          "401": {
            "description": "Credenciais inválidas"
          },
          "500": {
            "description": "Erro de servidor ou de armazenamento"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Serviço de gestão de webhooks (separado do host 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": [
                        "email.delivered",
                        "email.bounced"
                      ]
                    }
                  ],
                  "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é **apresentado apenas uma vez** — armazene-o imediatamente do lado do servidor. Utilize-o para\nverificar a assinatura HMAC de cada payload recebido.\n\n**Limites**: máx. 20 webhooks por conta, máx. 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": [
                  "email.delivered",
                  "email.bounced"
                ],
                "description": "Integração com o Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook criado — `secret` é devolvido apenas aqui",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "email.delivered",
                    "email.bounced"
                  ],
                  "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 inválido, lista de eventos inválida ou limite excedido"
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "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": "Atualizar um webhook",
        "description": "Atualização parcial — só os campos enviados são modificados.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook atualizado",
            "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 todo o seu histórico de entregas.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Eliminado"
          },
          "404": {
            "description": "Webhook não encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "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 de assinatura antes de depender de 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/v2",
          "description": "Serviço de gestão de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Rodar o segredo HMAC",
        "description": "Gera um novo segredo HMAC e invalida imediatamente o antigo.\nO novo segredo é devolvido **uma única vez** na resposta — armazene-o. Todas\nas entregas a partir deste momento serão assinadas com o novo segredo.\n\nUtilize esta operaçã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/v2",
          "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 das tentativas de despacho deste webhook (retenção de 30 dias).\nÚtil para depuração — que eventos foram enviados, códigos de estado recebidos,\nnúmero de retentativas, 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/v2",
          "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 reativar uma entrega falhada depois de corrigir o seu endpoint.\nÉ criada uma NOVA linha `Webhook_Delivery` (a original é preservada\npara auditoria). A repetição segue a política de retentativas padrão\n(mesmo esquema de backoff, mesma regra de desativação automática apó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"
          }
        }
      }
    }
  }
}