{
  "openapi": "3.0.3",
  "info": {
    "title": "Mailpro™ Email API v2",
    "version": "2",
    "description": "La API Email v2 de Mailpro™ le permite gestionar mediante programación listas de contactos, plantillas\nde correo, direcciones de remitente y campañas, así como enviar tanto correos masivos como transaccionales.\n\n## Autenticación\n\nTodos los endpoints aceptan **tres métodos de autenticación**. Utilice el que mejor se adapte\na su stack.\n\n- **OAuth 2.0**: tokens con scopes, revocables, para aplicaciones de terceros y\n  plataformas de integración (Zapier, Make, n8n). Es el único método que puede confiar a\n  un tercero. **Los tokens OAuth se controlan por scope en cada endpoint** (véase más abajo).\n- **Bearer JWT** (heredado): un token HMAC obtenido con `POST /token`, sin scopes.\n- **IdClient + ApiKey** (heredado): identificador de cliente + clave API.\n\n> El Bearer JWT heredado e IdClient+ApiKey siguen funcionando sin cambios y **no** están\n> sujetos a los scopes. Solo los tokens de acceso OAuth 2.0 están sujetos a los controles de scope\n> por endpoint indicados en cada operación más abajo.\n\n### Método 1 — OAuth 2.0 (recomendado para integraciones)\n\nMailpro utiliza **un único** servidor de autorización OAuth 2.0 para todas sus API, en una\nsuperficie única e independiente de la versión: **`https://api.mailpro.com/oauth/`**. No existe\nun endpoint OAuth por versión: usted obtiene un token en `/oauth/token` y el\n**mismo** token funciona en esta API Email v2, en CRM v3 y en SMS. Los\nendpoints a los que puede llamar dependen de los **scopes** del token, no de la URL base\nde la API. Emisor (claim `iss`): `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Autorización | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / renovación | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Descubrimiento | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nGrants: `authorization_code` **+ PKCE (S256, obligatorio)**, `client_credentials`,\n`refresh_token` (rotación). Duración del token de acceso: **20 min**; token de actualización: **30 días**\n(deslizantes, de un solo uso); código de autorización: **60 s**.\n\n**Inicio rápido: obtener un token y llamar a esta API** (sustituya los valores; nunca\nhaga commit de un secreto 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\nDespués llame a esta API con `Authorization: Bearer ACCESS_TOKEN`. El mismo token\nfunciona en las API CRM v3 y SMS. Un token al que le falte el scope exigido por un\nendpoint recibe **403 `insufficient_scope`**. Recorrido completo y catálogo de scopes:\nconsulte la documentación de la API **CRM v3** › Autenticación. Scopes útiles para el 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 (heredado)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nObtenga un token mediante `POST /token` (codificado como formulario, 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\nEl mismo token también es válido en la API CRM v3 y en la API SMS:\nautentíquese una sola vez y llame a cualquier API. Los tokens son válidos durante **30 días** de forma predeterminada;\nutilice `grant_type=refresh_token` para renovarlos sin volver a autenticarse. Sin scopes:\nprefiera OAuth 2.0 para las integraciones instalables.\n\n### Método 3 — IdClient + ApiKey\n\nDos credenciales:\n\n| Parámetro  | Tipo    | Descripción |\n|------------|---------|-------------|\n| `IdClient` | entero  | Su identificador numérico de cliente Mailpro, disponible en **Configuración → Acceso API** |\n| `ApiKey`   | cadena  | Su clave de API, disponible en **Configuración → Acceso API** |\n\nEnvíelas en uno cualquiera de estos lugares — elija solo uno:\n\n1. **Cabeceras HTTP (recomendado)** — `IdClient: 12345` y `ApiKey: a1b2c3d4-…`.\n   Las URL quedan registradas por los servidores web, las CDN y los proxies, de modo que una clave incluida en la cadena de consulta\n   puede filtrarse en los registros de acceso. Las cabeceras no se registran.\n2. **Cadena de consulta (heredado, sigue funcionando)** — `?IdClient=12345&ApiKey=…`.\n   Se conserva por compatibilidad con integraciones existentes. Migre a\n   cabeceras lo antes posible.\n3. **Cuerpo del formulario (solo POST)** — `IdClient=12345&ApiKey=…` en\n   `application/x-www-form-urlencoded`.\n\nSi proporciona las credenciales en más de un lugar, **prevalece la cabecera**.\n\n### Control de scopes OAuth por endpoint (Email v2)\n\nPara los tokens emitidos por OAuth, cada grupo de endpoints exige un scope (la autenticación\nheredada está exenta). Cada operación indica su scope en **Authorization**. Resumen:\n\n| Endpoints | Scope requerido |\n|-----------|-----------------|\n| `/send/*` (campañas, transaccional, programación, prueba — salvo `/send/{IdSend}/status`) | `email:send` |\n| `/stats/*` (salvo `/stats/del`), `/history/list`, `/send/{IdSend}/status` | `email:read` |\n| `/message/*`, `/senderEmail/*` (lectura) | `email:templates:read` |\n| `/message/*`, `/senderEmail/*` (add/edit/del), `/stats/del` | `email:templates:write` |\n| `/list/list`, `/email/list` | `contacts:read` |\n| `/list/{add,edit,del}`, `/email/{add,addSingle,edit,del}`, `/import/upload` | `contacts:write` |\n| `/account/*` | `account:read` |\n\nUn rechazo por scope devuelve **403** con\n`{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }`.\n\n## Formato de respuesta\n\nTodos los endpoints admiten `json` (predeterminado) y `xml`. Especifique el formato en la URL:\n- `/email/list.json`\n- `/email/list.xml`\n\n## Paginación\n\n**Misma regla en las tres API de Mailpro** (Email v2, CRM v3, SMS): **5000 elementos por página,\npor defecto y como máximo.**\n- `numberOfRecords` — elementos por página. Ausente, `0` o por encima de 5000 = 5000.\n- `pageNumber` — número de página a partir de 1 (por defecto 1).\n- Ambos se aceptan como parámetro de query **o** como cabecera HTTP.\n- Una página llena significa que puede haber más: pida la página siguiente hasta recibir\n  una página incompleta.\n- Las páginas son estables: una misma llamada devuelve los mismos elementos, en el mismo orden,\n  mientras los datos no cambien entretanto.\n- Excepción: las listas de mensajes y de historial con su HTML (`bodyHTML=true`) devuelven 10 elementos por página.\n- `/email/list` añade `X-Total-Count` (el total real) y `X-Truncated: true` cuando quedan contactos\n  más allá de la página.\n\n**Parámetros desconocidos**: se ignoran, nunca se rechazan. Cuando una solicitud lleva un parámetro que la API\nno reconoce, la respuesta incluye `X-Ignored-Parameters` (los nombres) y `X-Documentation` (un enlace a\nesta página), para que un error tipográfico no pase desapercibido.\n\n## Respuestas de error\n\n| HTTP | Significado |\n|------|-------------|\n| 400  | Solicitud incorrecta — falta un parámetro obligatorio o es inválido |\n| 401  | No autorizado — `IdClient` o `ApiKey` no válidos |\n| 403  | Prohibido — se ha alcanzado el límite de la cuenta (p. ej., número máximo de listas) |\n| 404  | No encontrado — el recurso solicitado no existe |\n| 500  | Error interno del servidor |\n\nErrores derivados de las reglas de negocio:\n- `\"Not enough credit available.\"` → 403 — su cuenta no dispone de créditos de correo restantes\n- `\"Email address unsubscribed.\"` → 400 — el destinatario se ha dado de baja\n\n## Seguimiento de entrega (emails transaccionales)\n\nCada email enviado **de forma unitaria** (`POST /send/sendmail`, la API CRM v3, el relé SMTP o una automatización) recibe un identificador. Puede seguirse hasta que el servidor del destinatario lo acepte o lo rechace. Las campañas no están cubiertas aquí: utilice las estadísticas.\n\n1. **Envíe**: la respuesta de `POST /send/sendmail.{format}` contiene el identificador del envío.\n2. **Reciba el resultado** (recomendado): los eventos webhook `email.delivered` y `email.bounced` envían el estado final a su servidor en cuanto se conoce, sin ninguna consulta.\n3. **O consulte**: `GET /send/{IdSend}/status.{format}` devuelve el estado actual (tabla más abajo).\n\n| `status` | Significado | ¿Final? |\n|---|---|---|\n| `queued` | Aceptado, en espera de envío. | no |\n| `scheduled` | Programado para más tarde (`DatePlanned`). | no |\n| `sent` | Entregado por nuestros servidores, aún sin respuesta del servidor del destinatario. | no |\n| `delivered` | Aceptado por el servidor del destinatario (`DiagCode` = su respuesta SMTP). | **sí** |\n| `bounced` | Rechazado. `BounceType`: `hard` = dirección no válida o rechazo definitivo; `soft` = rechazo tras nuevos intentos (buzón lleno, servidor inaccesible…). | **sí** |\n| `not_found` | Identificador desconocido o que no pertenece a su cuenta. | **sí** |\n\n**Consultar sin entrar en bucle**\n\n- Deje de consultar en cuanto el estado sea **final**: ya no cambiará.\n- Primera consulta, como pronto, **5 minutos** después del envío: `delivered` aparece unos 5 minutos después de la entrega.\n- Después, **una consulta cada 15 minutos como máximo**.\n- Si consulta un envío no final antes de 15 minutos, recibe la misma respuesta con la cabecera `Retry-After` (el número de segundos que debe esperar), y la llamada no cuenta en su cuota.\n- **Como máximo 48 horas** después del envío, cada email tiene un estado final: más allá, no consulte más.\n- `scheduled`: no es necesario consultar antes de `DatePlanned`.\n- **Cada consulta cuenta en su cuota de peticiones a la API.** Siguiendo estas reglas, un envío cuesta como máximo 192 peticiones (4 por hora durante 48 horas), y muchas menos en la práctica, ya que se detiene en el estado final. El mismo seguimiento por webhook cuesta un único evento.\n\nLos estados se conservan durante **365 días**.\n\n## Webhooks\n\nMailpro™ puede notificar a su servidor en tiempo real cuando se producen ciertos eventos en su\ncuenta (un correo se entrega, una campaña finaliza, un contacto rebota, etc.).\nAl estilo de Stripe: su URL recibe un POST firmado con HMAC-SHA256 en cuanto se dispara\nel evento.\n\nCada evento enviado a su webhook cuenta como 1 petición en su cuota de peticiones a la API.\n\n### Cómo funciona\n\n1. **Suscríbase** a uno o varios tipos de evento mediante `POST /webhooks`. La respuesta\n   contiene un `secret` que se muestra **una única vez** (al estilo de Stripe / GitHub): consérvelo.\n2. **Mailpro envía un POST** con una carga útil JSON firmada a su URL en cuanto un evento coincide.\n3. **Verifique la firma** en el lado del servidor con su `secret` (fragmentos a continuación).\n4. **Responda con 200–299** en un plazo de 10 segundos. De lo contrario, reintentaremos con retroceso\n   exponencial (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, y después abandonamos).\n\n> **⏱ Retardo de activación** — tras crear, actualizar o eliminar un webhook, el\n> cambio tarda hasta **10 minutos** en propagarse por los servidores de la API de Mailpro.\n> Durante ese intervalo, los eventos pueden no coincidir todavía con su nueva suscripción\n> (o pueden seguir coincidiendo con una que acaba de eliminarse). Ese es el tiempo necesario para\n> refrescar la caché en memoria de suscripciones en cada instancia de la API.\n\n### Envoltorio de la carga útil\n\nTodos los eventos comparten un envoltorio común:\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 | Descripción |\n|-------|---------|-------------|\n| `id` | `evt_` + 32 hex | Identificador único del evento — utilícelo como clave de idempotencia en su lado. |\n| `type` | `<domain>.<verb>` | Tipo de evento canónico. |\n| `created` | Segundos Unix UTC | Se incluye en la firma HMAC. |\n| `apiVersion` | `\"v2\"` | Indica qué API de Mailpro publicó el evento. |\n| `account.id` | int | Su identificador de cliente Mailpro (= `IdClient`). |\n| `account.name` | string | El nombre de su cuenta (útil para depuración en el lado cliente). |\n| `data` | object | Carga útil del evento — la estructura depende de `type` (consulte el catálogo a continuación). |\n\n### Catálogo de eventos\n\n| Evento | Disparador | Estructura de `data` |\n|--------|------------|----------------------|\n| `ping` | Prueba mediante `POST /webhooks/{id}/test` | `{ message }` |\n| `email.processed` | Envío aceptado por la canalización | `{ messageId, email, campaignId, processedAt }` |\n| `email.delivered` | Un correo **individual** fue aceptado por el servidor del destinatario — API v2/v3, SMTP o Automation (**no** campañas). Emitido desde el flujo de entrega de PowerMTA. | `{ messageId, email, idSending, sendingType, diagCode, deliveredAt }` |\n| `email.opened` | Impacto en el píxel de seguimiento | `{ messageId, email, campaignId, openedAt, ip, userAgent }` |\n| `email.clicked` | Clic en un enlace rastreado | `{ messageId, email, campaignId, clickedAt, url, ip, userAgent }` |\n| `email.bounced` | Rebote duro o blando | `{ messageId, email, campaignId, bouncedAt, bounceType, reason }` |\n| `email.spam_report` | Reclamación FBL | `{ messageId, email, campaignId, reportedAt }` |\n| `email.unsubscribed` | Clic en el enlace de baja | `{ messageId, email, campaignId, unsubscribedAt }` |\n| `email.dropped` | Rechazado antes del envío | `{ messageId, email, campaignId, droppedAt, reason }` |\n| `campaign.started` | Comienza la distribución | `{ campaignId, name, totalRecipients, startedAt }` |\n| `campaign.finished` | Todos los destinatarios procesados | `{ campaignId, name, totalSent, totalFailed, finishedAt }` |\n| `credits.low` | El saldo de créditos de correo está por debajo de su umbral de alerta | `{ remaining, threshold }` |\n\nSuscríbase a todos los eventos de esta API pasando `[\"*\"]` en el array `events`.\n\n### Firma HMAC\n\nCada POST incluye una cabecera `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. Extraiga `t` y `v1` de la cabecera.\n2. **Rechace** la solicitud si `|now - t| > 300` (ventana de protección contra repetición de 5 minutos).\n3. Calcule `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Compare en tiempo constante** `v1` con `expected` (`crypto.timingSafeEqual`,\n   `hash_equals`, `CryptographicOperations.FixedTimeEquals`) — nunca con `==`.\n\n#### Node.js\n\n```js\nconst crypto = require('crypto');\n\nfunction verifyMailproSignature(rawBody, header, secret) {\n  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));\n  if (Math.abs(Date.now() / 1000 - parseInt(parts.t)) > 300) return false;\n  const expected = crypto\n    .createHmac('sha256', secret)\n    .update(parts.t + '.' + rawBody)\n    .digest('hex');\n  return crypto.timingSafeEqual(\n    Buffer.from(parts.v1, 'hex'),\n    Buffer.from(expected, 'hex'));\n}\n```\n\n#### PHP\n\n```php\nfunction verifyMailproSignature(string $rawBody, string $header, string $secret): bool {\n    parse_str(str_replace(',', '&', $header), $p);\n    if (abs(time() - (int)$p['t']) > 300) return false;\n    $expected = hash_hmac('sha256', $p['t'] . '.' . $rawBody, $secret);\n    return hash_equals($expected, $p['v1']);\n}\n```\n\n#### Python\n\n```python\nimport hmac, hashlib, time\n\ndef verify_mailpro_signature(raw_body: bytes, header: str, secret: str) -> bool:\n    parts = dict(p.split('=') for p in header.split(','))\n    t = int(parts['t'])\n    if abs(time.time() - t) > 300:\n        return False\n    expected = hmac.new(\n        secret.encode(),\n        f\"{t}.\".encode() + raw_body,\n        hashlib.sha256\n    ).hexdigest()\n    return hmac.compare_digest(expected, parts['v1'])\n```\n\n#### C#\n\n```csharp\nusing System.Security.Cryptography;\nusing System.Text;\n\nstatic bool VerifyMailproSignature(string rawBody, string header, string secret) {\n    var parts = header.Split(',')\n        .Select(p => p.Split('='))\n        .ToDictionary(a => a[0], a => a[1]);\n    var t = long.Parse(parts[\"t\"]);\n    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return false;\n    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));\n    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes($\"{t}.{rawBody}\"));\n    var expected = Convert.ToHexString(hash).ToLowerInvariant();\n    return CryptographicOperations.FixedTimeEquals(\n        Encoding.UTF8.GetBytes(expected),\n        Encoding.UTF8.GetBytes(parts[\"v1\"]));\n}\n```\n\n### Reintentos y desactivación automática\n\n| Intento | Retardo antes del siguiente intento |\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 (la entrega se marca como `failed`) |\n\nTras **10 fallos consecutivos** en el mismo webhook, este se **desactiva\nautomáticamente** (`isActive: false`) y recibirá un correo de notificación. Vuelva a activarlo\ncon `PUT /webhooks/{id}` una vez que su endpoint esté reparado.\n\n### Éxito = HTTP 2xx\n\nConsideramos que su webhook se ha procesado correctamente solo si devuelve un estado en el rango `200–299`.\nCualquier 3xx/4xx/5xx o un tiempo de espera agotado (> 10 s) se considera un fallo y dispara reintentos.\nSi su endpoint está permanentemente inactivo, devuelva `410 Gone` de forma explícita: los reintentos\nseguirán produciéndose, pero el motivo del fallo quedará más claro en su registro de entregas.\n\n### Límites\n\n| Límite | Valor |\n|--------|-------|\n| Webhooks por cuenta | 20 |\n| Eventos suscritos por webhook | 50 |\n| Tamaño máximo de la carga útil | 256 KB |\n| Tiempo de espera HTTP por intento | 10 segundos |\n| Retención del historial de entregas | 30 días |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/v2",
      "description": "Producción"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token Bearer JWT obtenido mediante `POST /v2/token` (codificado en formulario,\ngrant password). El mismo token también es válido en la CRM API v3 y la SMS\nAPI: autentíquese una sola vez y llame a cualquier API.\nPáselo así: `Authorization: Bearer <token>`\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 de Mailpro — la forma moderna de que las aplicaciones de terceros y las plataformas\nde integración (Zapier, Make, n8n) actúen en nombre de un usuario de Mailpro con\ntokens de acceso revocables y delimitados por scopes.\n\n- **authorizationCode + PKCE** (S256, obligatorio para clientes públicos) — el\n  flujo de consentimiento «Conectar Mailpro». Emite un token de acceso + un\n  refresh token rotativo.\n- **clientCredentials** — máquina a máquina, sin intervención del usuario.\n\nUn único servidor de autorización para todas las APIs, en la superficie neutra respecto a la versión\n`https://api.mailpro.com/oauth/` (emisor / claim `iss`\n`https://api.mailpro.com/oauth/`). Los tokens de acceso son JWT RS256\n(verificables frente al JWKS en `https://api.mailpro.com/oauth/.well-known/jwks`);\nTTL **20 minutos**. Los refresh tokens son válidos durante **30 días** (deslizante) y\nson de **un solo uso** (se rotan en cada renovación). Los códigos de autorización viven\n**60 segundos**.\n\nEl mismo token de acceso OAuth es aceptado por las tres APIs de Mailpro\n(CRM v3, Email v2, SMS) — autentíquese una vez y llame a cualquier API; el acceso\nse rige por los scopes del token, no por la URL base de la API. La autenticación\nheredada (Bearer JWT / IdClient+ApiKey) sigue funcionando sin cambios y NO\nestá restringida por scopes.\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": "Su ID numérico de cliente Mailpro — transporte **preferido** (cabecera HTTP).\nLas URL quedan registradas por los servidores web, Cloudflare y los proxies,\nasí que las credenciales en la cadena de consulta pueden filtrarse en los\nregistros de acceso. Las cabeceras no se registran.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "ApiKey",
        "description": "Su clave de API (GUID) — transporte **preferido** (cabecera HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "IdClient",
        "description": "Su ID numérico de cliente Mailpro — método **heredado**, mantenido por\ncompatibilidad retroactiva. Cuando pueda, cambie a la cabecera `IdClient`.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "ApiKey",
        "description": "Su clave de API (GUID) — método **heredado**, mantenido por compatibilidad retroactiva.\n"
      }
    },
    "parameters": {
      "format": {
        "name": "format",
        "in": "path",
        "required": true,
        "description": "Formato de respuesta",
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "xml"
          ],
          "default": "json"
        },
        "example": "json"
      },
      "numberOfRecords": {
        "name": "numberOfRecords",
        "in": "query",
        "description": "Elementos por página — 5000 por defecto y como máximo (véase Paginación).",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 50
      },
      "pageNumber": {
        "name": "pageNumber",
        "in": "query",
        "description": "Número de página (comienza en 1). El valor predeterminado es 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Token de acceso JWT — utilícelo como `Authorization: Bearer <token>` en las solicitudes posteriores."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Vigencia del token en segundos",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "ID de cliente del usuario autenticado",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Token para obtener un nuevo token de acceso sin volver a autenticarse"
          },
          "application": {
            "type": "string",
            "description": "Nombre de la integración (solo para concesiones de terceros)",
            "nullable": true
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "ListID": {
            "type": "integer",
            "description": "Identificador único de la lista",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias heredado** — mismo valor que `ListID`. Se devuelve por compatibilidad retroactiva con clientes antiguos.",
            "example": 101
          },
          "Title": {
            "type": "string",
            "description": "Nombre para mostrar de la lista",
            "example": "Newsletter — France"
          },
          "Type": {
            "type": "integer",
            "description": "`0` = lista de contactos estándar, `1` = lista negra (para la gestión de bajas)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "NumberEmails": {
            "type": "integer",
            "description": "Número total de contactos en esta lista",
            "example": 4521
          },
          "CreationDate": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha y hora de creación de la lista",
            "example": "2025-01-15T10:30:00"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "IDMessage": {
            "type": "integer",
            "description": "Identificador único de la plantilla de mensaje",
            "example": 501
          },
          "Subject": {
            "type": "string",
            "description": "Asunto del correo electrónico",
            "example": "Spring Newsletter — April 2026"
          },
          "Language": {
            "type": "string",
            "description": "Código de idioma utilizado para la localización del enlace de baja",
            "example": "EN"
          },
          "LinkAlign": {
            "type": "string",
            "description": "Alineación horizontal del enlace de baja",
            "enum": [
              "left",
              "center",
              "right"
            ],
            "example": "center"
          },
          "LinkUp": {
            "type": "integer",
            "description": "Posición del enlace de baja — `0` = abajo, `1` = arriba",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "BodyHTML": {
            "type": "string",
            "description": "Contenido HTML completo del correo (devuelto únicamente cuando `bodyHTML=true`)",
            "example": "<h1>Welcome!</h1><p>This is our spring newsletter.</p>"
          },
          "UpdateDate": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha y hora de la última modificación de la plantilla",
            "example": "2026-03-10T14:22:00"
          }
        }
      },
      "SenderEmail": {
        "type": "object",
        "properties": {
          "IDEmailExp": {
            "type": "integer",
            "description": "Identificador único de la dirección de correo del remitente",
            "example": 201
          },
          "Email": {
            "type": "string",
            "description": "Dirección de correo del remitente (debe estar verificada antes de su uso)",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nombre para mostrar como remitente en los clientes de correo de los destinatarios",
            "example": "Your Company Newsletter"
          },
          "IsValid": {
            "type": "boolean",
            "description": "`true` si la dirección de correo ha sido verificada por 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 de este envío o campaña",
            "example": 3001
          },
          "ListID": {
            "type": "integer",
            "description": "ID de la lista de destinatarios utilizada",
            "example": 101
          },
          "AddressBookID": {
            "type": "integer",
            "description": "**Alias heredado** — mismo valor que `ListID`.",
            "example": 101
          },
          "IDCampaign": {
            "type": "integer",
            "description": "ID del registro de estadísticas de la campaña (si se ha definido Campaign=1 en el momento del envío)",
            "example": 8001
          },
          "SenderEmail": {
            "type": "string",
            "description": "Dirección de correo del remitente",
            "example": "newsletter@yourcompany.com"
          },
          "SenderName": {
            "type": "string",
            "description": "Nombre para mostrar del remitente",
            "example": "Your Company Newsletter"
          },
          "DatePlanned": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha y hora de envío programadas",
            "example": "2026-04-20T09:00:00"
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Asunto del correo electrónico",
            "example": "Spring Newsletter — April 2026"
          },
          "NumberCredit": {
            "type": "integer",
            "description": "Número de créditos de correo consumidos por este envío",
            "example": 4521
          }
        }
      },
      "HistoryEntry": {
        "type": "object",
        "properties": {
          "IDHistoric": {
            "type": "integer",
            "description": "Identificador único de esta entrada del historial",
            "example": 9001
          },
          "SubjectMessage": {
            "type": "string",
            "description": "Asunto del correo enviado",
            "example": "Spring Newsletter — April 2026"
          },
          "DateSend": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha y hora de envío del correo",
            "example": "2026-04-20T09:00:01"
          },
          "NumberSend": {
            "type": "integer",
            "description": "Número total de correos enviados en esta campaña",
            "example": 4521
          },
          "NumberOpen": {
            "type": "integer",
            "description": "Número de aperturas únicas registradas",
            "example": 1823
          },
          "NumberClick": {
            "type": "integer",
            "description": "Número de clics únicos en enlaces registrados",
            "example": 342
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "ID del webhook (Mailpro)",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS que recibe los eventos",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipos de eventos suscritos",
            "example": [
              "email.delivered",
              "email.bounced",
              "campaign.finished"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Slack integration"
          },
          "is_active": {
            "type": "boolean",
            "description": "Cuando es `false`, no se entrega ningún evento. Se desactiva automáticamente tras 10 fallos consecutivos.",
            "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": "Cuándo se intentó la última entrega",
            "example": "2026-07-21T18:56:07.653"
          },
          "last_delivery_status": {
            "type": "integer",
            "nullable": true,
            "description": "Estado HTTP devuelto por su endpoint en la última entrega",
            "example": 200
          },
          "consecutive_failures": {
            "type": "integer",
            "description": "Se restablece a 0 en el primer éxito; en 10 el webhook se desactiva automáticamente",
            "example": 0
          }
        }
      },
      "WebhookList": {
        "type": "object",
        "description": "Envoltura devuelta por `GET /webhooks`.",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "total": {
            "type": "integer",
            "description": "Número total de webhooks en la cuenta",
            "example": 2
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint HTTPS (HTTP rechazado en producción)",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "Lista de tipos de eventos a los que suscribirse (véase el catálogo anterior). Utilice `[\"*\"]` para suscribirse a todos los eventos de esta 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": "Secreto HMAC. **Se muestra una sola vez aquí, nunca más.** Almacénelo en el servidor.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Actualización parcial — todos los campos son opcionales.",
        "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": "Establezca `true` para reactivar un webhook desactivado automáticamente una vez corregido su 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": "Obtenga un token Bearer JWT para autenticar todas las demás llamadas a la API.\nEl endpoint `/token` de v2 es una redirección 307 al emisor canónico\n`/v3/token` — su cliente HTTP sigue la redirección de forma transparente (se\nconservan el método POST y el cuerpo).\n"
    },
    {
      "name": "Account",
      "description": "Consulte su saldo de créditos de correo, su cuota mensual de API y el estado de su suscripción."
    },
    {
      "name": "Lists",
      "description": "Gestione las listas (listas de contactos). Una lista agrupa contactos para campañas masivas.\n**Máximo de 1000 listas por cuenta** (mismo límite en las tres API de Mailpro y en la app).\n`Type 0` = lista estándar. `Type 1` = lista negra (utilizada para la gestión de bajas).\n"
    },
    {
      "name": "Contacts",
      "description": "Gestione contactos de correo individualmente. Los contactos pertenecen a una o varias listas.\nUtilice la importación masiva (`/email/add`) para grandes lotes, o la adición de un\núnico contacto (`/email/addSingle`) para inscripciones individuales con valores de\ncampos personalizados.\n"
    },
    {
      "name": "Messages",
      "description": "Gestione plantillas de correo HTML. Una plantilla de mensaje almacena el asunto del correo,\nel cuerpo HTML y la configuración del enlace de baja.\nLas plantillas se reutilizan en distintas campañas.\n"
    },
    {
      "name": "Campaigns",
      "description": "Envíe campañas masivas de correo a una lista y gestione los envíos programados.\nUna campaña utiliza una plantilla de mensaje y una dirección de remitente.\n"
    },
    {
      "name": "Transactional",
      "description": "Envíe correos transaccionales puntuales a destinatarios individuales.\nA diferencia de las campañas, los correos transaccionales no requieren una lista:\nse pasan directamente el correo del destinatario y el cuerpo HTML.\n"
    },
    {
      "name": "Sender Addresses",
      "description": "Liste y gestione las direcciones de correo de remitente validadas.\nSolo las direcciones verificadas pueden utilizarse como dirección `From` en las campañas.\n"
    },
    {
      "name": "Statistics",
      "description": "Acceda a las métricas de rendimiento por campaña: aperturas, clics, rebotes y más.\nDisponibles desgloses detallados por hora, día, país, sistema operativo y cliente de correo.\n"
    },
    {
      "name": "History",
      "description": "Consulte el registro completo de todos los envíos de correo anteriores.\n"
    },
    {
      "name": "Import",
      "description": "Cargue un archivo CSV o XLSX para importar contactos de correo en una lista de forma masiva.\nEl archivo se pone en cola para su procesamiento asíncrono — siga la finalización mediante\nel `ImportJobId` devuelto o a través de la devolución de llamada `WebhookUrl` opcional.\n"
    },
    {
      "name": "Webhooks",
      "description": "Suscriba su servidor a notificaciones de eventos en tiempo real. Mailpro envía mediante POST\nuna carga JSON firmada con HMAC a su URL en cuanto se produce el evento suscrito.\nConsulte la sección «Webhooks» de la introducción para ver el catálogo completo de eventos,\nel sobre de la carga útil, fragmentos de verificación de firma y la política de reintentos.\n"
    },
    {
      "name": "Suppression",
      "description": "Rebotes y bajas de la cuenta: listar, añadir, eliminar."
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getEmailAccessToken",
        "summary": "Obtener token de acceso (redirección 307 a /v3/token)",
        "security": [],
        "description": "Obtiene un token Bearer JWT utilizando las credenciales de cliente de Mailpro.\nPase el `access_token` devuelto como `Authorization: Bearer <token>` en todas\nlas solicitudes posteriores. El mismo token también es válido en la CRM API v3 y\nla SMS API.\n\n> **⚙ Detalle de implementación** — `POST /v2/token` es una **redirección\n> temporal 307** a `POST /v3/token` (configurada en la capa de reescritura\n> de IIS `web.config`). HTTP 307 conserva tanto el **método** (`POST`)\n> como el **cuerpo de la solicitud**, de modo que cualquier cliente HTTP\n> conforme con el estándar sigue la redirección de forma transparente —\n> usted continúa enviando POST a `/v2/token` y recibe un JWT válido a\n> cambio. No hay lógica de emisión de tokens duplicada; la Email API v2\n> nunca emite tokens por sí misma.\n\n### Tipos de concesión admitidos\n| Tipo de concesión | Caso de uso |\n|------------|----------|\n| `password` | Integración estándar — nombre de usuario + clave de API |\n| `refresh_token` | Renovar un token de acceso que está a punto de expirar sin volver a autenticarse |\n| `client_credentials` | Servidor a servidor solo con el ID de cliente |\n\n### Vigencia del token\n- Token de acceso: **30 días**\n- Token de actualización: **90 días**\n\nUtilice `grant_type=refresh_token` para renovar el token de acceso sin\nvolver a autenticarse. Almacene los tokens en el servidor (Vault, variables\nde entorno); no los incruste nunca en JS de navegador ni en binarios de\naplicaciones móviles. Consulte la documentación de `/token` de la CRM API v3\npara ver la nota de seguridad completa.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "password",
                      "refresh_token",
                      "client_credentials"
                    ],
                    "example": "password"
                  },
                  "username": {
                    "type": "string",
                    "description": "Su nombre de usuario de Mailpro (correo electrónico). Obligatorio para la concesión `password`.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "Su clave de API de Mailpro (formato GUID). Obligatorio para la concesión `password`.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Token de actualización anterior. Obligatorio para la concesión `refresh_token`."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Su ID de cliente de Mailpro (entero). Obligatorio para la concesión `client_credentials`.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token emitido correctamente. Devuelto por `POST /v3/token` tras seguir\nde forma transparente la redirección 307 — su cliente HTTP ve una\nrespuesta 200 normal con la misma forma de cuerpo que recibiría\ndirectamente del endpoint de tokens 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": "Redirección temporal a `POST /v3/token`, emitida por la regla de\nreescritura de IIS en `web.config`. Los clientes HTTP conformes con\nel estándar la siguen automáticamente y conservan el método POST\noriginal y el cuerpo del formulario. Solo es visible para los clientes\nque desactivan explícitamente el seguimiento de redirecciones\n(p. ej. `curl --max-redirs 0`).\n",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "example": "https://api.mailpro.com/v3/token"
              }
            }
          },
          "400": {
            "description": "Credenciales no válidas o tipo de concesión no admitido",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Credenciales incorrectas",
                    "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": "Obtener saldo de créditos de correo",
        "description": "Devuelve el saldo restante de créditos de correo de su cuenta de Mailpro.\nCada correo enviado consume un crédito. Los créditos no expiran con la suscripción,\npero solo pueden utilizarse mientras esta esté activa.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo de créditos devuelto correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Credits": 48500
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/account/subscriptionEndDate.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSubscriptionEndDate",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtener fecha de finalización de la suscripción",
        "description": "Devuelve la fecha de caducidad de la suscripción actual de Mailpro.\nDespués de la fecha de caducidad, los envíos quedan bloqueados hasta que se renueve la suscripción.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Fecha de finalización de la suscripción devuelta correctamente",
            "content": {
              "application/json": {
                "example": {
                  "SubscriptionEndDate": "2027-01-15T00:00:00"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtener cuota mensual de API",
        "description": "Devuelve la cuota mensual de solicitudes de API del cliente autenticado.\n\n**Cálculo de la cuota:** el límite se calibra a partir de los créditos\nde correo de la suscripción (normalmente `subscription_credits × 5`).\nPara un plan de 10 000 correos al mes, esto da un presupuesto mensual\nde 50 000 solicitudes. Se restablece en la **fecha de aniversario de la\nsuscripción** (no el día 1 del mes natural).\n\n**Qué consume créditos:**\n- Cada solicitud autenticada a los endpoints `v2`, `v3` o `sms` de la API.\n- Cada evento de webhook enviado a un endpoint suscrito.\n\n**Qué es GRATIS (no consume créditos):**\n- Los endpoints `/health`.\n- Las solicitudes que fallan con `401`, `403` o `429`.\n- Los eventos de webhook para clientes sin suscripción coincidente.\n\nLa cuota se **comparte entre las 3 APIs de Mailpro** (`v2`, `v3`, `sms`)\n— un cliente = un presupuesto mensual para toda la plataforma.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Instantánea de la cuota",
            "content": {
              "application/json": {
                "example": {
                  "MonthlyLimit": 50000,
                  "Remaining": 32847,
                  "Used": 17153,
                  "IsFree": false,
                  "RemainedSendsForFree": 0
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "No se ha encontrado registro de cuota (cuenta recién creada; la fila se creará en la primera solicitud autenticada)."
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listLists",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar todas las listas",
        "description": "Devuelve todas las listas de la cuenta, ordenadas por fecha de creación (las más recientes primero),\na menos que se haya establecido `sortByName=true`.\nUtilice `type=0` para las listas normales o `type=1` para las listas negras.\n\n> **Alias heredado:** `/addressbook/list.{format}` — mismo endpoint, mantenido por\n> compatibilidad retroactiva. Las nuevas integraciones deben utilizar `/list/*`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleFilter",
            "in": "query",
            "description": "Filtrar por título (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`0` = solo listas estándar, `1` = solo listas negras. Omítalo para devolver todas.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Establezca `true` para ordenar los resultados alfabéticamente por título",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listas devueltas correctamente.\n\n> La respuesta también contiene un campo duplicado heredado `AddressBookList` (contenido idéntico)\n> y cada elemento incluye un duplicado heredado `AddressBookID` (idéntico a `ListID`). Las nuevas\n> integraciones deben ignorarlos.\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": "Credenciales no válidas"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Crear una lista",
        "description": "Crea una nueva lista (lista de contactos).\nLa lista comienza vacía — añada contactos con `/email/add` o `/email/addSingle`.\n**Máximo de 1000 listas por cuenta** (mismo límite en las tres API de Mailpro y en la app). Devuelve HTTP 422 si se alcanza el límite.\n\n> **Alias heredado:** `/addressbook/add.{format}` — mismo endpoint, mantenido por compatibilidad retroactiva.\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": "Nombre para mostrar de la nueva lista",
                    "example": "Spring Campaign 2026"
                  },
                  "Type": {
                    "type": "integer",
                    "description": "`0` = lista estándar (predeterminado), `1` = lista negra",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista creada correctamente.\n\n> También se devuelve un campo duplicado heredado `AddressBookList` (contenido 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": "Falta el Title"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "422": {
            "description": "Límite de listas (1000) alcanzado"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Renombrar una lista",
        "description": "Actualiza el título de una lista existente.\nLos contactos que contiene no se ven afectados.\n\n> **Alias heredado:** `/addressbook/edit.{format}` — mismo endpoint, mantenido por compatibilidad retroactiva.\n> El nombre de parámetro `AddressBookID` también se acepta como alias heredado 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 de la lista que se va a renombrar (de `/list/list`). También se acepta el alias heredado `AddressBookID`.",
                    "example": 101
                  },
                  "Title": {
                    "type": "string",
                    "description": "Nuevo título de la lista",
                    "example": "Newsletter — Europe"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista renombrada correctamente"
          },
          "400": {
            "description": "Falta ListID o Title"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Lista no encontrada"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar una lista",
        "description": "Elimina permanentemente una lista **y todos los contactos que contiene**.\nEsta acción no se puede deshacer.\n\n> **Alias heredado:** `/addressbook/del.{format}` — mismo endpoint, mantenido por compatibilidad retroactiva.\n> El nombre de parámetro `AddressBookID` también se acepta como alias heredado 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 de la lista que se va a eliminar. También se acepta el alias heredado `AddressBookID`.",
                    "example": 101
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista eliminada correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "Falta ListID"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Lista no encontrada"
          }
        }
      }
    },
    "/email/list.{format}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "listEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar contactos",
        "description": "Devuelve una lista paginada de contactos de correo de la cuenta.\nFiltre por lista o por patrón de correo.\nLos resultados se ordenan alfabéticamente cuando `sortByName=true`; de lo contrario, por orden de inserción.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtrar por dirección de correo (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "@gmail.com"
          },
          {
            "name": "listId",
            "in": "query",
            "description": "Devolver solo los contactos de esta lista. También se acepta el alias heredado `addressBookId`.",
            "schema": {
              "type": "integer"
            },
            "example": 101
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Establezca `true` para ordenar los resultados alfabéticamente por dirección de correo",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de contactos devuelta correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Emails": [
                    {
                      "IdEmail": 10001,
                      "Email": "alice@example.com",
                      "Field1": "Alice",
                      "Field2": "Dupont"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/email/add.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addEmails",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Importar contactos (masivo)",
        "description": "Importa una o varias direcciones de correo en una lista en una única solicitud.\nProporcione las direcciones en `EmailList` separadas por punto y coma.\n\n**Ejemplo:** `alice@example.com;bob@example.com;carol@example.com`\n\nEste endpoint solo importa direcciones de correo. Para establecer también valores de campos\npersonalizados, utilice `/email/addSingle` para cada contacto.\n\nLas direcciones dadas de baja anteriormente se omiten silenciosamente a menos que se establezca `Force=1`.\n\n**Selección de lista:** proporcione `ListId` (o su alias heredado `AddressBookId`). Es necesario al menos uno.\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 de la lista de destino. También se acepta el alias heredado `AddressBookId`.",
                    "example": 101
                  },
                  "EmailList": {
                    "type": "string",
                    "description": "Direcciones de correo separadas por punto y coma que se van a importar",
                    "example": "alice@example.com;bob@example.com;carol@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Establezca `1` para volver a importar direcciones que se habían dado de baja anteriormente.\nPredeterminado: `0` (las direcciones dadas de baja se omiten).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contactos importados correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "3 contacts imported"
                }
              }
            }
          },
          "400": {
            "description": "Falta EmailList"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/email/addSingle.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "addSingleEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Añadir un único contacto",
        "description": "Añade un contacto a una lista con valores de campos personalizados opcionales.\n\n`Field1` a `Field25` se asignan a las definiciones de columnas personalizadas de su lista.\nLa asignación depende del orden en que se hayan definido las columnas — consulte la configuración\nde su lista en la interfaz de Mailpro para ver qué número de campo corresponde a cada columna\n(por ejemplo, Field1 = FirstName, Field2 = LastName, Field3 = City…).\n\n**Selección de lista:** proporcione `ListId` (o su alias heredado `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 de la lista de destino. También se acepta el alias heredado `AddressBookId`.",
                    "example": 101
                  },
                  "Email": {
                    "type": "string",
                    "description": "Dirección de correo del nuevo contacto",
                    "example": "alice@example.com"
                  },
                  "Force": {
                    "type": "integer",
                    "description": "Establezca `1` para volver a añadir una dirección dada de baja anteriormente",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Valor del campo personalizado 1 (la asignación de columnas depende de su lista)",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Valor del campo personalizado 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Valor del campo personalizado 3",
                    "example": "Paris"
                  },
                  "Field4": {
                    "type": "string",
                    "description": "Valor del campo personalizado 4"
                  },
                  "Field5": {
                    "type": "string",
                    "description": "Valor del campo personalizado 5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacto añadido correctamente",
            "content": {
              "application/json": {
                "example": {
                  "EmailId": 10002,
                  "Email": "alice@example.com",
                  "Field1": "Alice",
                  "Field2": "Dupont",
                  "ListID": 101
                }
              }
            }
          },
          "400": {
            "description": "Falta Email"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/email/edit.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "editEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Actualizar un contacto",
        "description": "Actualiza la dirección de correo o los valores de los campos personalizados de un contacto existente.\nIdentifique el contacto mediante `EmailId` (de `/email/list`).\nTanto `EmailId` como `Email` son obligatorios.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "EmailId",
                  "Email"
                ],
                "properties": {
                  "EmailId": {
                    "type": "integer",
                    "description": "ID del contacto que se va a actualizar (de `/email/list`)",
                    "example": 10001
                  },
                  "Email": {
                    "type": "string",
                    "description": "Nueva dirección de correo del contacto",
                    "example": "alice.updated@example.com"
                  },
                  "Field1": {
                    "type": "string",
                    "description": "Nuevo valor del campo personalizado 1",
                    "example": "Alice"
                  },
                  "Field2": {
                    "type": "string",
                    "description": "Nuevo valor del campo personalizado 2",
                    "example": "Dupont"
                  },
                  "Field3": {
                    "type": "string",
                    "description": "Nuevo valor del campo personalizado 3"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacto actualizado correctamente"
          },
          "400": {
            "description": "Falta EmailId o Email"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Contacto no encontrado"
          }
        }
      }
    },
    "/email/del.{format}": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "deleteEmail",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar un contacto",
        "description": "Elimina permanentemente un contacto por su 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 del contacto que se va a eliminar (de `/email/list`)",
                    "example": 10001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacto eliminado correctamente"
          },
          "400": {
            "description": "Falta EmailId"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Contacto no encontrado"
          }
        }
      }
    },
    "/message/list.{format}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar plantillas de mensaje",
        "description": "Devuelve las plantillas de correo HTML guardadas de la cuenta.\nDe forma predeterminada, el cuerpo HTML **no** se incluye en la respuesta para mantener cargas útiles pequeñas.\nEstablezca `bodyHTML=true` para incluirlo (limita automáticamente los resultados a 10 por página).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectFilter",
            "in": "query",
            "description": "Filtrar por asunto (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Establezca `true` para incluir el cuerpo HTML completo en cada resultado.\nCuando es `true`, los resultados se limitan automáticamente a 10 por página, independientemente de `numberOfRecords`.\n",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Plantillas de mensaje devueltas correctamente",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/message/add.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "addMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Crear una plantilla de mensaje",
        "description": "Crea una nueva plantilla de correo HTML.\nLa plantilla almacena el asunto, el cuerpo HTML y los ajustes del enlace de baja.\nUna vez creada, utilice el `IDMessage` devuelto al lanzar una campaña.\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": "Asunto del correo electrónico (máx. 255 caracteres)",
                    "example": "Spring Newsletter — April 2026"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenido HTML completo del cuerpo del correo",
                    "example": "<h1>Spring is here!</h1><p>Check out our latest offers.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Código de idioma para la localización del enlace de baja (p. ej. `EN`, `FR`, `DE`)",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "description": "Alineación horizontal del enlace de baja",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "description": "Posición del enlace de baja — `0` = parte inferior del correo, `1` = parte superior",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plantilla de mensaje creada correctamente",
            "content": {
              "application/json": {
                "example": {
                  "IDMessage": 502,
                  "Subject": "Spring Newsletter — April 2026",
                  "Language": "EN",
                  "LinkAlign": "center",
                  "LinkUp": 0
                }
              }
            }
          },
          "400": {
            "description": "Falta un campo obligatorio"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/message/edit.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "editMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Actualizar una plantilla de mensaje",
        "description": "Actualiza el contenido y los metadatos de una plantilla de mensaje 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 de la plantilla de mensaje que se va a actualizar (de `/message/list`)",
                    "example": 501
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Nuevo asunto del correo electrónico",
                    "example": "Spring Newsletter — April 2026 (revised)"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Nuevo contenido HTML del cuerpo del correo",
                    "example": "<h1>Spring is here!</h1><p>Updated content.</p>"
                  },
                  "Language": {
                    "type": "string",
                    "description": "Código de idioma para la localización del enlace de baja",
                    "example": "EN"
                  },
                  "LinkAlign": {
                    "type": "string",
                    "enum": [
                      "left",
                      "center",
                      "right"
                    ],
                    "example": "center"
                  },
                  "LinkUp": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plantilla de mensaje actualizada correctamente"
          },
          "400": {
            "description": "Falta un campo obligatorio"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Plantilla de mensaje no encontrada"
          }
        }
      }
    },
    "/message/del.{format}": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "deleteMessage",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar una plantilla de mensaje",
        "description": "Elimina permanentemente una plantilla de mensaje por su identificador único.\nNo se pueden eliminar las plantillas utilizadas por campañas programadas pendientes.\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 de la plantilla de mensaje que se va a eliminar (de `/message/list`)",
                    "example": 501
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plantilla de mensaje eliminada correctamente"
          },
          "400": {
            "description": "Falta MessageId"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Plantilla de mensaje no encontrada"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar campañas programadas",
        "description": "Devuelve la lista de campañas de correo programadas y procesadas recientemente.\nLos resultados se ordenan por fecha de envío prevista (las más recientes primero).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtrar por asunto de la campaña (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de campañas devuelta correctamente",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/campaign.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Lanzar una campaña",
        "description": "Programa o envía inmediatamente una campaña de correo a una lista\nutilizando una plantilla de mensaje guardada y una dirección de remitente.\n\n**Obligatorio:**\n- `IDMessage` — la plantilla que se va a enviar (de `/message/list`)\n- `IDEmailExp` — la dirección de remitente que se va a utilizar (de `/senderEmail/list`)\n- `ListId` — la lista de destinatarios (de `/list/list`). También se acepta el alias heredado `IDAddressBook`.\n\n**Programación:** establezca `DatePlanned` en una fecha/hora ISO 8601 futura para programar el envío.\nOmita `DatePlanned` para enviar inmediatamente.\n\n**Seguimiento de estadísticas:** establezca `Campaign=1` y proporcione un `TitleCampaign` para activar\nel seguimiento de aperturas/clics/rebotes en la sección Estadí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 de la lista de destinatarios (de `/list/list`). También se acepta el alias heredado `IDAddressBook`.",
                    "example": 101
                  },
                  "IDMessage": {
                    "type": "integer",
                    "description": "ID de la plantilla de mensaje que se va a enviar (de `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID de la dirección de correo del remitente que se va a utilizar (de `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDUnsubscribeList": {
                    "type": "integer",
                    "description": "Lista utilizada para recopilar los contactos dados de baja (lista negra).\nTambién se acepta el alias heredado `IDUnsubscribeAddressBook`.\n",
                    "example": 102
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Fecha/hora de envío programadas (ISO 8601). Omítalo para enviar inmediatamente.",
                    "example": "2026-04-20T09:00:00"
                  },
                  "Campaign": {
                    "type": "integer",
                    "description": "Establezca `1` para realizar el seguimiento de este envío como una campaña con nombre en las estadísticas",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 1
                  },
                  "TitleCampaign": {
                    "type": "string",
                    "description": "Título de la campaña mostrado en las estadísticas (obligatorio cuando `Campaign=1`)",
                    "example": "Spring Newsletter April 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaña programada o enviada correctamente.\n\n> La respuesta también devuelve los alias heredados `AddressBookID` y `UnsubscribeAddressBookID`\n> (idénticos a `ListID` / `UnsubscribeListID`). Las nuevas integraciones deben ignorarlos.\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": "Falta IDMessage o IDEmailExp"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "403": {
            "description": "Créditos de correo insuficientes"
          },
          "404": {
            "description": "Lista, mensaje o remitente no encontrados"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "deleteCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar o eliminar una campaña",
        "description": "Cancela un envío de campaña **programado pendiente** o elimina uno **completado**.\nSolo se pueden cancelar los envíos programados para una fecha futura — los envíos en curso no se pueden detener.\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 del envío de campaña que se va a cancelar o eliminar (de `/send/list`)",
                    "example": 3001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaña cancelada o eliminada correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Campaign Deleted"
                }
              }
            }
          },
          "400": {
            "description": "Falta IdSend"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Campaña no encontrada"
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "listScheduledCampaigns",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar mis campañas de correo programadas",
        "description": "Devuelve las campañas de correo y los envíos individuales programados para una fecha futura\nque aún no se han enviado. Útil antes de llamar a `/cancel` o `/reschedule`.\nLos registros se ordenan por `DatePlanned` en orden ascendente.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de campañas / envíos programados.\n\n> Cada registro también incluye los alias heredados `AddressBookID` y\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": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/{IdSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "cancelScheduledCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar una campaña / envío programado",
        "description": "Cancela un envío de correo programado (campaña o individual) que aún no se ha despachado.\nSi el envío ya se ha enviado (o no existe / pertenece a otro cliente),\ndevuelve **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Envío cancelado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 5001
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "409": {
            "description": "Ya enviado o no encontrado"
          }
        }
      }
    },
    "/send/{IdSend}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "rescheduleCampaign",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reprogramar una campaña / envío programado",
        "description": "Actualiza el `DatePlanned` de un envío de correo programado. La nueva fecha debe ser\n**futura** y estar **dentro de los próximos 90 días**.\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": "Envío reprogramado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSend": 5001,
                  "NewPlanDate": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "PlanDate no proporcionado o no válido"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "409": {
            "description": "Ya enviado, no encontrado o nueva fecha fuera de rango (debe ser futura y estar dentro de los próximos 90 días)"
          }
        }
      }
    },
    "/send/mail/scheduled.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "listScheduledMails",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar los correos individuales programados",
        "description": "Devuelve los correos individuales enviados con `/send/sendmail` y una fecha futura que aún no han salido. Las campañas se listan con `/send/scheduled`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Correos programados devueltos",
            "content": {
              "application/json": {
                "example": {
                  "scheduledMails": [
                    {
                      "IdSingleSend": 880123,
                      "Email": "jane@example.com",
                      "Subject": "Your invoice",
                      "DatePlanned": "2026-12-01T09:00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/cancel.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "cancelMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar un correo individual programado",
        "description": "Cancela el correo mientras no haya salido.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` devuelto por `/send/sendmail`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Correo cancelado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 880123
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "409": {
            "description": "Envío no encontrado o ya realizado"
          }
        }
      }
    },
    "/send/mail/{IdSingleSend}/reschedule.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "rescheduleMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reprogramar un correo individual programado",
        "description": "Cambia la fecha de envío. La nueva fecha debe ser futura y estar dentro de 90 días. También se acepta `PATCH`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSingleSend",
            "in": "path",
            "required": true,
            "description": "`IdSingleSend` devuelto 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": "Nueva fecha de envío (ISO 8601)",
                    "example": "2026-12-15T09:00:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Correo reprogramado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "IdSingleSend": 880123,
                  "NewPlanDate": "2026-12-15T09:00:00"
                }
              }
            }
          },
          "400": {
            "description": "Fecha ausente o no válida"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "409": {
            "description": "Envío no encontrado, ya realizado o fecha fuera de los límites"
          }
        }
      }
    },
    "/send/sendingTest.{format}": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "sendTestEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar un correo de prueba",
        "description": "Envía una vista previa de una plantilla de mensaje a un destinatario especificado para su revisión\nantes de lanzar la campaña real.\nEl remitente, la plantilla y el destinatario de la prueba se identifican mediante sus ID.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "MessageId",
                  "IDEmailExpFrom",
                  "IDEmailExpTo"
                ],
                "properties": {
                  "MessageId": {
                    "type": "integer",
                    "description": "ID de la plantilla de mensaje que se va a previsualizar (de `/message/list`)",
                    "example": 501
                  },
                  "IDEmailExpFrom": {
                    "type": "integer",
                    "description": "ID de la dirección de remitente que se va a utilizar (de `/senderEmail/list`)",
                    "example": 201
                  },
                  "IDEmailExpTo": {
                    "type": "integer",
                    "description": "ID de la dirección de remitente destinataria — el correo de prueba se envía a esta dirección",
                    "example": 202
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Correo de prueba enviado correctamente",
            "content": {
              "application/json": {
                "example": {
                  "SendingTest": {
                    "IdSendingTest": 7001,
                    "ToEmail": "test@yourcompany.com",
                    "FromEmail": "newsletter@yourcompany.com",
                    "SenderName": "Your Company Newsletter"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Falta un campo obligatorio"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/sendmail.{format}": {
      "post": {
        "tags": [
          "Transactional"
        ],
        "operationId": "sendTransactionalEmail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar un correo transaccional",
        "description": "Envía un correo transaccional puntual a uno o varios destinatarios.\nA diferencia de las campañas, este endpoint no requiere una lista —\nla dirección del destinatario y el cuerpo HTML se pasan directamente.\n\n**Obligatorio:**\n- `IDEmailExp` — el ID de la dirección de remitente (de `/senderEmail/list`)\n- `EmailData` — destinatario en formato `email,field1,field2,...,field25` (separado por comas)\n- `BodyHTML` — el cuerpo HTML\n- `Subject` — el asunto\n\n**Formato de EmailData:** `alice@example.com,Alice,Dupont,Paris`\nEl primer valor es la dirección de correo; los valores 2 a 26 se asignan a Field1–Field25 para\nlas variables de personalización de su plantilla HTML.\n\n**Múltiples destinatarios:** separe varias entradas de `EmailData` con punto y coma:\n`alice@example.com,Alice;bob@example.com,Bob`\n\n**Programación:** establezca `DatePlanned` en una fecha/hora ISO 8601 futura, u omítalo para enviar inmediatamente.\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 de la dirección de correo del remitente que se va a utilizar (de `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinatario en formato `email,campo1,campo2,...,campo25` (separados por comas).\nEl primer valor es la dirección de correo; los demás son campos de personalización\nasignados a Field1–Field25 en tu plantilla HTML.\n\n**La parte local** del correo (antes de `@`) acepta letras, dígitos y\n`. _ - +` — incluido el sub-addressing RFC 5322 (`user+tag@domain`, p. ej. Gmail,\nFastmail, Proton). Los demás caracteres especiales que permite la RFC 5322\n(p. ej. `! # $ % & ' * / = ? ^ { | } ~`) y las partes locales entre comillas **no**\nse aceptan.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenido HTML completo del cuerpo del correo",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Asunto del correo electrónico (máx. 255 caracteres)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "array",
                    "maxItems": 5,
                    "description": "Archivos adjuntos opcionales — envía la solicitud como `multipart/form-data` y añade una parte de archivo por adjunto (cualquier nombre de campo). Hasta **5 archivos**, **10 MB por archivo**, **15 MB en total**. Tipos aceptados: PDF, Word, Excel, PowerPoint, imágenes (JPG, PNG, GIF, WebP), ZIP, CSV, TXT — los archivos ejecutables y scripts se rechazan. **Facturación:** el envío mantiene su crédito habitual, más **1 crédito por cada 512 KB de adjuntos más allá de los primeros 512 KB** (los adjuntos ≤ 512 KB no añaden nada). Todos los demás campos de este endpoint (`ReplyTo`, `ActivateStatistics`, `CustomHeaders`, …) funcionan exactamente igual que en la variante form-urlencoded.",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (por defecto): los archivos adjuntos solo se usan para este envío — se almacenan fuera de\nsu cuenta, no cuentan en su cuota de almacenamiento y se eliminan automáticamente después de\n35 días. `true`: los archivos adjuntos también se guardan en los archivos de su cuenta (carpeta\n`Secure/Files/Sending/api`) y cuentan en su cuota de almacenamiento.\n",
                    "example": false
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "IDEmailExp",
                  "EmailData",
                  "BodyHTML",
                  "Subject"
                ],
                "properties": {
                  "IDEmailExp": {
                    "type": "integer",
                    "description": "ID de la dirección de correo del remitente que se va a utilizar (de `/senderEmail/list`)",
                    "example": 201
                  },
                  "EmailData": {
                    "type": "string",
                    "description": "Destinatario en formato `email,campo1,campo2,...,campo25` (separados por comas).\nEl primer valor es la dirección de correo; los demás son campos de personalización\nasignados a Field1–Field25 en tu plantilla HTML.\n\n**La parte local** del correo (antes de `@`) acepta letras, dígitos y\n`. _ - +` — incluido el sub-addressing RFC 5322 (`user+tag@domain`, p. ej. Gmail,\nFastmail, Proton). Los demás caracteres especiales que permite la RFC 5322\n(p. ej. `! # $ % & ' * / = ? ^ { | } ~`) y las partes locales entre comillas **no**\nse aceptan.\n",
                    "example": "alice@example.com,Alice,Dupont,Paris"
                  },
                  "BodyHTML": {
                    "type": "string",
                    "description": "Contenido HTML completo del cuerpo del correo",
                    "example": "<p>Hello {{Field1}}, your order has been confirmed.</p>"
                  },
                  "Subject": {
                    "type": "string",
                    "description": "Asunto del correo electrónico (máx. 255 caracteres)",
                    "example": "Your order #12345 is confirmed"
                  },
                  "attachments": {
                    "type": "string",
                    "description": "Archivos adjuntos opcionales como un **array JSON** de objetos `{ \"filename\": …, \"content\": … }`, con `content` **codificado en Base64** (mismo formato que la API CRM v3). Hasta **5 archivos**, **10 MB por archivo** y **15 MB en total** (tras la decodificación). Se aceptan los formatos habituales de documentos e imágenes; los archivos ejecutables y scripts se rechazan. **Facturación:** el envío mantiene su 1 crédito habitual, más **1 crédito por cada 512 KB de adjuntos más allá de los primeros 512 KB**. *También puedes enviar los archivos como partes `multipart/form-data` (consulta el cuerpo de la solicitud multipart más arriba) — ambos funcionan.*",
                    "example": "[{\"filename\":\"invoice.pdf\",\"content\":\"JVBERi0xLjQK...\"}]"
                  },
                  "KeepInMyFiles": {
                    "type": "boolean",
                    "default": false,
                    "description": "`false` (por defecto): los archivos adjuntos solo se usan para este envío — se almacenan fuera de\nsu cuenta, no cuentan en su cuota de almacenamiento y se eliminan automáticamente después de\n35 días. `true`: los archivos adjuntos también se guardan en los archivos de su cuenta (carpeta\n`Secure/Files/Sending/api`) y cuentan en su cuota de almacenamiento.\n",
                    "example": false
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Fecha/hora de envío programadas (ISO 8601). Omítalo para enviar inmediatamente.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "ActivateStatistics": {
                    "type": "boolean",
                    "description": "Establezca `true` para realizar el seguimiento de aperturas y clics de este correo",
                    "default": false,
                    "example": true
                  },
                  "ReplyTo": {
                    "type": "string",
                    "description": "Dirección de correo de respuesta. Si se omite, las respuestas van a la dirección del remitente.",
                    "example": "support@yourcompany.com"
                  },
                  "UnsubscriptionLink": {
                    "type": "boolean",
                    "description": "Establezca `true` para añadir un enlace de baja al cuerpo del correo",
                    "default": false,
                    "example": false
                  },
                  "CustomHeaders": {
                    "type": "string",
                    "description": "Cabeceras SMTP adicionales como una cadena `key=value` separada por punto y coma",
                    "example": "X-Campaign-ID=campaign_42;X-Priority=1"
                  },
                  "BodyText": {
                    "type": "string",
                    "description": "Versión de texto plano de reserva para los clientes de correo que no renderizan HTML",
                    "example": "Hello Alice, your order has been confirmed."
                  },
                  "List_Unsubscribe": {
                    "type": "string",
                    "description": "Valor para la cabecera de correo `List-Unsubscribe` (URL o mailto)",
                    "example": "https://yourcompany.com/unsubscribe?token=abc123"
                  },
                  "List_Unsubscribe_Post": {
                    "type": "string",
                    "description": "Valor para la cabecera `List-Unsubscribe-Post` (RFC 8058)",
                    "example": "List-Unsubscribe=One-Click"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Correo transaccional enviado o programado correctamente",
            "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": "Falta un campo obligatorio o formato de correo no válido"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "403": {
            "description": "Créditos de correo insuficientes"
          },
          "404": {
            "description": "Remitente no encontrado o dirección de correo dada de baja"
          }
        }
      }
    },
    "/send/{IdSend}/status.{format}": {
      "get": {
        "tags": [
          "Transactional"
        ],
        "operationId": "getTransactionalStatus",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtener el estado de entrega de un correo transaccional",
        "description": "Devuelve el estado de entrega actual de un correo transaccional enviado con `/send/sendmail`. Pase el `IdSingleSend` que devolvió esa llamada.\n\nValores posibles: `delivered` (aceptado por el servidor del destinatario, véase `DiagCode`), `bounced` (rechazado — `BounceType: hard` dirección no válida o rechazo definitivo, `soft` rechazo tras nuevos intentos), `sent` (entregado al servidor de correo, aún sin respuesta), `scheduled` (aún no enviado, `DatePlanned` en el futuro) y `queued` (en espera de envío). `delivered` y `bounced` son finales: deje de consultar. Cada email tiene un estado final como máximo 48 horas después del envío; consulte cada 15 minutos como máximo (cada llamada cuenta en su cuota de la API) o utilice los webhooks `email.delivered` / `email.bounced`. Solo el cliente que envió el email puede leer su estado — cualquier otro id devuelve 404.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSend",
            "in": "path",
            "required": true,
            "description": "El `IdSingleSend` devuelto por `/send/sendmail`.",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Estado de entrega actual",
            "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": "Credenciales no válidas"
          },
          "404": {
            "description": "No se encontró ningún envío transaccional con 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 direcciones de remitente validadas",
        "description": "Devuelve la lista de direcciones de correo de remitente configuradas para la cuenta.\nSolo las direcciones con `IsValid: true` se pueden utilizar al enviar campañas.\nLas nuevas direcciones se añaden con `/senderEmail/add` y son válidas una vez que se hace clic en el enlace del correo de validación.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "emailFilter",
            "in": "query",
            "description": "Filtrar por dirección de correo (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "@yourcompany.com"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Establezca `true` para ordenar los resultados alfabéticamente por nombre del remitente",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Direcciones de remitente devueltas correctamente",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/senderEmail/add.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "addSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Añadir una dirección de remitente",
        "description": "Añade la dirección con los mismos controles que la aplicación y le envía un correo de validación. Se puede utilizar una vez que se haga clic en el enlace de ese correo. Una cuenta puede tener hasta 25 remitentes, validados o pendientes.",
        "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": "Dirección del remitente",
                    "example": "news@example.com"
                  },
                  "SenderName": {
                    "type": "string",
                    "description": "Nombre mostrado a los destinatarios",
                    "example": "Example News"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dirección añadida. `DomainHasMx` es false cuando el dominio no tiene registro MX.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true,
                  "DomainHasMx": true
                }
              }
            }
          },
          "400": {
            "description": "Falta `Email` o `SenderName`"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "422": {
            "description": "Dirección rechazada: no válida, ya entre los remitentes de la cuenta, dominio de correo público, nombre prohibido o límite de 25 alcanzado. El mensaje indica el motivo."
          },
          "503": {
            "description": "No disponible temporalmente, inténtelo de nuevo"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/resendValidation.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "resendSenderValidation",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar de nuevo el correo de validación",
        "description": "Para una dirección que aún espera la validación.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID del remitente, de `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Correo enviado de nuevo",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ConfirmationSent": true
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Remitente no encontrado"
          },
          "409": {
            "description": "Este remitente ya está validado"
          },
          "503": {
            "description": "No disponible temporalmente, inténtelo de nuevo"
          }
        }
      }
    },
    "/senderEmail/{IdSenderEmail}/authentication.{format}": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "getSenderAuthentication",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Comprobar el dominio de un remitente (SPF, DKIM, DMARC, MX)",
        "description": "Comprueba el dominio en directo en el DNS y devuelve los registros que hay que publicar. Solo lectura. El DKIM se activa en la aplicación: `DkimSettingsUrl` abre la pantalla correcta.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "IdSenderEmail",
            "in": "path",
            "required": true,
            "description": "ID del remitente, de `/senderEmail/list`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Estado del dominio. `Spf.RecommendedRecord` se crea a partir de su registro actual: publíquelo solo si `Spf.ChangeNeeded` es 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": "Credenciales no válidas"
          },
          "404": {
            "description": "Remitente no encontrado"
          },
          "503": {
            "description": "No disponible temporalmente, inténtelo de nuevo"
          }
        }
      }
    },
    "/senderEmail/del.{format}": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "deleteSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar una dirección de remitente",
        "description": "Elimina una dirección de correo de remitente validada de la cuenta.\nNo se pueden eliminar las direcciones de remitente utilizadas por campañas programadas.\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 de la dirección de remitente que se va a eliminar (de `/senderEmail/list`)",
                    "example": 201
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dirección de remitente eliminada correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "EmailSender Deleted"
                }
              }
            }
          },
          "400": {
            "description": "Falta idEmailExp"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/list.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "listStats",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar estadísticas de campañas",
        "description": "Devuelve las métricas de rendimiento globales de todas las campañas: número de envíos, tasa de apertura,\ntasa de clics, número de rebotes. Filtre por rango de fechas o título de campaña.\nLos resultados se ordenan por fecha de envío (los más recientes primero).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "titleCampaignFilter",
            "in": "query",
            "description": "Filtrar por título de la campaña (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "spring"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "dateStart",
            "in": "query",
            "description": "Inicio del filtro de rango de fechas (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-01-01T00:00:00"
          },
          {
            "name": "dateEnd",
            "in": "query",
            "description": "Fin del filtro de rango de fechas (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-12-31T23:59:59"
          }
        ],
        "responses": {
          "200": {
            "description": "Estadísticas de campaña devueltas correctamente",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/byHour.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByHour",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Estadísticas por hora",
        "description": "Devuelve el desglose por hora de aperturas y clics de una campaña concreta.\nÚtil para comprender el momento óptimo de envío.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID de la campaña (de `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Estadísticas por hora devueltas correctamente",
            "content": {
              "application/json": {
                "example": {
                  "ByHour": [
                    {
                      "Hour": 9,
                      "Opens": 823,
                      "Clicks": 142
                    },
                    {
                      "Hour": 10,
                      "Opens": 512,
                      "Clicks": 98
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/byDay.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "getStatsByDay",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Estadísticas por día",
        "description": "Devuelve el desglose diario de aperturas y clics de una campaña concreta.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "description": "ID de la campaña (de `/stats/list`)",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Estadísticas diarias devueltas correctamente"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/del.{format}": {
      "post": {
        "tags": [
          "Statistics"
        ],
        "operationId": "deleteStats",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar estadísticas de campaña",
        "description": "Elimina permanentemente todos los registros estadísticos de una campaña determinada.",
        "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 de la campaña cuyas estadísticas se van a eliminar (de `/stats/list`)",
                    "example": 8001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estadísticas de campaña eliminadas correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Statistic Deleted"
                }
              }
            }
          },
          "400": {
            "description": "Falta IdCampaign"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Campaña no encontrada"
          }
        }
      }
    },
    "/stats/country.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsCountry",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Desglose por geolocalización",
        "description": "Devuelve el desglose por geolocalización de las aperturas de campaña — cuántas aperturas\nproceden de cada país.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Desglose por país devuelto"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/open.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsOpens",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registro de eventos de apertura",
        "description": "Devuelve el registro por destinatario de los eventos de apertura de una campaña (una fila por apertura).\nUtilice `emailFilter` para buscar un destinatario concreto (coincidencia parcial, no distingue mayúsculas y 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 apertura devueltos"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/click.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsClicks",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registro de eventos de clic",
        "description": "Devuelve el registro por destinatario de los eventos de clic de una campaña — incluyendo\nqué enlace se ha pulsado y cuándo.\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 clic devueltos"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/system.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsSystem",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Desglose por sistema operativo",
        "description": "Devuelve el desglose de las aperturas por sistema operativo (Windows, macOS, iOS,\nAndroid, Linux, etc.) para una campaña determinada.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Desglose por SO devuelto"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/emailSoftware.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsEmailSoftware",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Desglose por cliente de correo",
        "description": "Devuelve el desglose de las aperturas por cliente de correo (Gmail, Outlook, Apple Mail,\nThunderbird, etc.) para una campaña determinada.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Desglose por cliente de correo devuelto"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/stats/bounce.{format}": {
      "get": {
        "tags": [
          "Statistics"
        ],
        "operationId": "statsBounce",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Registro de rebotes",
        "description": "Devuelve la lista de destinatarios rebotados (rebotes duros, rebotes blandos,\nquejas de spam) de una campaña, con el motivo del fallo para cada dirección.\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 rebote devueltos",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/suppression/bounces.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listBounces",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar los rebotes de la cuenta",
        "description": "Los más recientes primero. El total está en la cabecera `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type",
            "in": "query",
            "description": "`hard` o `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origen del rebote: `list`, `contact`, `api` o `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Dirección exacta",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "A partir de esta fecha",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Hasta esta fecha",
            "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": "Rebotes devueltos",
            "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` debe ser `hard` o `soft`"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar un rebote",
        "description": "`Source` y `Type` son obligatorios, tal como los devuelve `/suppression/bounces`: un `Id` por sí solo no es único.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` del rebote",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Source",
                  "Type"
                ],
                "properties": {
                  "Source": {
                    "type": "string",
                    "description": "`list`, `contact`, `api` o `smtp`"
                  },
                  "Type": {
                    "type": "string",
                    "enum": [
                      "hard",
                      "soft"
                    ],
                    "description": "`hard` o `soft`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rebote eliminado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": false
                }
              }
            }
          },
          "400": {
            "description": "Falta `Source` o `Type`"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Rebote no encontrado"
          }
        }
      }
    },
    "/suppression/bounces/{Id}/restore.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "restoreBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Volver a poner en sus listas un contacto con rebote duro",
        "description": "Solo para un rebote duro con el origen `contact`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` del rebote",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contacto repuesto",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 5521,
                  "Restored": true
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Rebote duro de un contacto no encontrado o dirección ya no activa"
          }
        }
      }
    },
    "/suppression/unsubscribers.{format}": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar las bajas de la cuenta",
        "description": "Los más recientes primero. El total está en la cabecera `X-Total-Count`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "source",
            "in": "query",
            "description": "Origen de la baja: `contact`, `list`, `smtp`, `api` o `api3`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Dirección exacta",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "A partir de esta fecha",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Hasta esta fecha",
            "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": "Bajas devueltas",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/suppression/unsubscribers/add.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "addUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Añadir una baja",
        "description": "Sin `ListId`, la dirección se da de baja de toda la cuenta. Con `ListId`, solo de esa lista de bajas.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Email"
                ],
                "properties": {
                  "Email": {
                    "type": "string",
                    "description": "Dirección que dar de baja",
                    "example": "stop@example.com"
                  },
                  "Comment": {
                    "type": "string",
                    "description": "Comentario libre",
                    "example": "Asked by phone"
                  },
                  "ListId": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Lista de bajas de la cuenta (opcional)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hecho. `AlreadyUnsubscribed` es true cuando la dirección ya estaba dada de baja.",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "AlreadyUnsubscribed": false
                }
              }
            }
          },
          "400": {
            "description": "Se requiere una dirección válida"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "`ListId` no es una lista de bajas de esta cuenta"
          }
        }
      }
    },
    "/suppression/unsubscribers/{Id}/del.{format}": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar una baja",
        "description": "`Source` es obligatorio, tal como lo devuelve `/suppression/unsubscribers`: un `Id` por sí solo no es único.",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "Id",
            "in": "path",
            "required": true,
            "description": "`Id` de la baja",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "Source"
                ],
                "properties": {
                  "Source": {
                    "type": "string",
                    "description": "`contact`, `list`, `smtp`, `api` o `api3`"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Baja eliminada",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Removed": 9012
                }
              }
            }
          },
          "400": {
            "description": "`Source` es obligatorio"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "Baja no encontrada"
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listHistory",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar el historial de envíos",
        "description": "Devuelve un registro paginado de todos los envíos de correo anteriores.\nFiltre por ID de campaña o por asunto.\nEstablezca `bodyHTML=true` para incluir el cuerpo HTML (limita automáticamente a 10 por página).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "subjectMessageFilter",
            "in": "query",
            "description": "Filtrar por asunto de la campaña (coincidencia parcial, no distingue mayúsculas y minúsculas)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "idCampaign",
            "in": "query",
            "description": "Devolver el historial solo de una campaña concreta",
            "schema": {
              "type": "integer"
            },
            "example": 8001
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "name": "bodyHTML",
            "in": "query",
            "description": "Establezca `true` para incluir el cuerpo HTML completo.\nLimita automáticamente los resultados a 10 por página.\n",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Historial devuelto correctamente",
            "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": "Credenciales no válidas"
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cargar un archivo de contactos (CSV / XLSX) para importación masiva",
        "description": "Cargue un archivo CSV o XLSX para importar contactos de correo en una lista.\nEl archivo se almacena y se pone en cola para su procesamiento asíncrono — el endpoint\ndevuelve un `ImportJobId` inmediatamente.\n\n**Tipo de solicitud:** `multipart/form-data`\n\n**Campos de formulario obligatorios:**\n- `IdClient` (entero) — su ID de cliente de Mailpro\n- `ApiKey` (cadena) — su clave de API\n- `ListId` (entero) — ID de la lista de destino. También se acepta el alias heredado `AddressBookId`.\n- `file` (binario) — el archivo CSV o XLSX que se va a cargar\n\n**Opcional:**\n- `WebhookUrl` (cadena) — URL HTTPS llamada cuando finaliza el procesamiento.\n  Recibe una carga útil JSON con el estado final (success / failed) y\n  los recuentos de filas importadas / omitidas / no válidas.\n\n**Formato del archivo:**\n- Codificado en UTF-8\n- Primera fila = cabeceras (una debe ser `Email` — no distingue mayúsculas y minúsculas)\n- Las demás columnas se asignan a los campos personalizados de la lista de destino\n- Tamaño máximo del archivo: 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 de la lista de destino. También se acepta el alias heredado `AddressBookId`.",
                    "example": 101
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Archivo CSV o XLSX (UTF-8, máx. 50 MB)"
                  },
                  "WebhookUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL de devolución de llamada invocada cuando finaliza el procesamiento",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Archivo aceptado y puesto en cola",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "ImportJobId": 13,
                  "InternalName": "230575-20260420140221-contacts.csv"
                }
              }
            }
          },
          "400": {
            "description": "Ningún archivo cargado o falta ListId"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "500": {
            "description": "Error del servidor o de almacenamiento"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servicio de gestión de webhooks (separado del host principal de la API)"
        }
      ],
      "get": {
        "summary": "Listar webhooks",
        "description": "Devuelve todos los webhooks configurados en la cuenta autenticada.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Matriz de webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "items": [
                    {
                      "id": 14,
                      "url": "https://example.com/hooks/mailpro",
                      "description": "Integración con 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": "Credenciales no válidas"
          }
        }
      },
      "post": {
        "summary": "Crear un webhook",
        "description": "Crea una nueva suscripción de webhook. La respuesta contiene un `secret` que\n**se muestra una sola vez** — guárdelo de inmediato en el servidor. Úselo para\nverificar la firma HMAC de cada carga útil entrante.\n\n**Límites**: máximo 20 webhooks por cuenta, máximo 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": "Integración con Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook creado — el `secret` solo se devuelve aquí",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "email.delivered",
                    "email.bounced"
                  ],
                  "description": "Integración con Slack",
                  "isActive": true,
                  "consecutiveFailures": 0,
                  "autoDisabledAt": null,
                  "autoDisabledReason": null,
                  "createdAt": "2026-05-25T10:00:00Z",
                  "updatedAt": "2026-05-25T10:00:00Z",
                  "secret": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
                }
              }
            }
          },
          "400": {
            "description": "URL, lista de eventos no válidas o límite superado"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servicio de gestión de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "summary": "Obtener un webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "El webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "404": {
            "description": "Webhook no encontrado"
          }
        }
      },
      "put": {
        "summary": "Actualizar un webhook",
        "description": "Actualización parcial — solo se modifican los campos enviados.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook actualizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "Carga útil no válida"
          },
          "404": {
            "description": "Webhook no encontrado"
          }
        }
      },
      "delete": {
        "summary": "Eliminar un webhook",
        "description": "Elimina permanentemente el webhook y todo su historial de entregas.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Eliminado"
          },
          "404": {
            "description": "Webhook no encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servicio de gestión de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Enviar un evento de prueba",
        "description": "Encola un evento `ping` inmediato (o cualquier otro tipo de evento mediante\nel campo del cuerpo `eventType`) a su endpoint. Útil para verificar la\naccesibilidad y la verificación de firmas antes de depender de eventos reales.\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 puesto en cola para su envío",
            "content": {
              "application/json": {
                "example": {
                  "deliveryId": 1234,
                  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
                  "eventType": "ping"
                }
              }
            }
          },
          "404": {
            "description": "Webhook no encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servicio de gestión de webhooks"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Rotar el secreto HMAC",
        "description": "Genera un nuevo secreto HMAC e invalida el antiguo de inmediato.\nEl nuevo secreto se devuelve **una sola vez** en la respuesta — guárdelo. A partir\nde ese momento, todas las entregas se firmarán con el nuevo secreto.\n\nUtilice esta función si sospecha que su secreto ha sido comprometido.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Nuevo secreto (visible una sola vez)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
                }
              }
            }
          },
          "404": {
            "description": "Webhook no encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servicio de gestión 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 paginación (= último ID de entrega visto). Devuelve las entregas con `id < cursor`."
        }
      ],
      "get": {
        "summary": "Listar intentos de entrega",
        "description": "Devuelve el historial de intentos de envío de este webhook (retención de 30 días).\nÚtil para la depuración — qué eventos se enviaron, códigos de estado recibidos,\nrecuentos de reintentos, mensajes de error.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Matriz de intentos de entrega (los más recientes primero)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook no encontrado"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v2",
          "description": "Servicio de gestión 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": "Reenviar una entrega",
        "description": "Encola un nuevo intento de entrega con la misma carga útil que el original.\nÚtil para volver a desencadenar una entrega fallida tras corregir su endpoint.\nSe crea una NUEVA fila `Webhook_Delivery` (la original se conserva\npara auditoría). El reenvío sigue la política de reintentos estándar\n(mismo calendario de retroceso, misma regla de desactivación automática tras 10 fallos).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Reenvío puesto en cola",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook o entrega no encontrados"
          }
        }
      }
    }
  }
}