{
  "openapi": "3.0.3",
  "info": {
    "title": "API SMS de Mailpro™",
    "version": "2",
    "description": "La API de SMS de Mailpro™ permite gestionar mediante programación listas de contactos telefónicos,\nnúmeros de teléfono y enviar mensajes SMS masivos o individuales.\n\n## Autenticación\n\nTodos los endpoints aceptan **tres métodos de autenticación**. Utilice el que mejor\nse adapte a su stack.\n\n- **OAuth 2.0** — tokens con ámbito y revocables para aplicaciones de terceros y\n  plataformas de integración (Zapier, Make, n8n). **Los tokens OAuth se restringen por scope\n  en cada endpoint** (véase a continuación).\n- **Bearer JWT** (heredado) — un token HMAC obtenido mediante `POST /token`, sin scopes.\n- **id_client + api_key** (heredado) — ID de cliente + clave de API.\n\n> Los métodos heredados Bearer JWT e id_client+api_key siguen funcionando sin cambios y **no**\n> se restringen por scope. Únicamente los tokens de acceso OAuth 2.0 están sujetos a\n> las comprobaciones de scope por endpoint que se muestran en cada operación a continuación.\n\n### Método 1 — OAuth 2.0 (recomendado para integraciones)\n\nMailpro opera **un único** servidor de autorización OAuth 2.0 para todas sus APIs, en una\núnica superficie sin distinción de versión: **`https://api.mailpro.com/oauth/`**. No existe\nun endpoint OAuth por versión: obtiene un token desde `/oauth/token` y el\n**mismo** token funciona en esta API de SMS, en el CRM v3 y en Email v2. Los\nendpoints a los que puede llamar se rigen por los **scopes** del token, no por la URL base\nde la API. Emisor (claim `iss`): `https://api.mailpro.com/oauth/`.\n\n| Endpoint | URL |\n|----------|-----|\n| Authorize | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / Refresh | `POST https://api.mailpro.com/oauth/token` |\n| JWKS | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Discovery | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nGrants: `authorization_code` **+ PKCE (S256, obligatorio)**, `client_credentials`,\n`refresh_token` (con rotación). TTL del token de acceso **20 min**; refresh token **30 días**\n(deslizante, de un solo uso); código de autorización **60 s**.\n\n**Inicio rápido — obtener un token e invocar esta API** (sustituya los marcadores; nunca\nincluya un secreto real en un commit):\n\n```bash\ncurl -X POST https://api.mailpro.com/oauth/token \\\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\n  -d \"grant_type=client_credentials\" \\\n  -d \"client_id=YOUR_CLIENT_ID\" \\\n  -d \"client_secret=YOUR_CLIENT_SECRET\" \\\n  -d \"scope=sms:send sms:read\"\n```\n\nA continuación, llame a esta API con `Authorization: Bearer ACCESS_TOKEN`. El mismo token\nfunciona en las APIs CRM v3 y Email v2. Un token que no disponga del scope requerido por un\nendpoint recibirá **403 `insufficient_scope`**. Recorrido completo del flujo y catálogo\nde scopes: consulte la documentación de la API **CRM v3** › Autenticación. Scopes\nrelevantes para SMS: `sms:send`, `sms:read`, `sms:contacts:read`, `sms:contacts:write`,\n`account:read`.\n\n### Método 2 — Bearer JWT (heredado)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nObtenga un token mediante `POST /token` (form-encoded, grant de contraseña OAuth2):\n\n```\nPOST https://api.mailpro.com/sms/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password&username=YOUR_USERNAME&password=YOUR_API_KEY\n```\n\nEl mismo token también es válido en la API CRM v3 y en la API Email v2:\nautentíquese una vez y llame a cualquier API. Los tokens son válidos durante **30 días** por defecto;\nutilice `grant_type=refresh_token` para renovarlo sin volver a autenticarse. No tiene scopes:\nprefiera OAuth 2.0 para integraciones instalables.\n\n### Método 3 — id_client + api_key\n\nDos credenciales:\n\n| Parámetro   | Tipo    | Descripción |\n|-------------|---------|-------------|\n| `id_client` | integer | Su ID numérico de cliente Mailpro, disponible en **Ajustes → Acceso a la API** |\n| `api_key`   | string  | Su clave de API (formato GUID), disponible en **Ajustes → Acceso a la API** |\n\nEnvíelas en cualquiera de estos lugares — elija uno:\n\n1. **Cabeceras HTTP (recomendado)** — `id_client: 12345` y `api_key: a1b2c3d4-…`.\n   Las URL son registradas por los servidores web, las CDN y los proxys, por lo que una clave en la query string\n   puede filtrarse en los registros de acceso. Las cabeceras no se registran.\n2. **Query string (heredado, sigue funcionando)** — `?id_client=12345&api_key=…`.\n   Se mantiene por compatibilidad con integraciones existentes. Migre a las\n   cabeceras tan pronto como pueda.\n3. **Cuerpo JSON / form (solo POST)** — mismos nombres de campo dentro del cuerpo de la petición.\n\nSi proporciona credenciales en más de un lugar, **prevalece la cabecera**.\n\n### Aplicación de scopes OAuth por endpoint (SMS)\n\nPara los tokens emitidos por OAuth, cada grupo de endpoints requiere un scope (la autenticación\nheredada queda exenta). Cada operación indica su scope en **Authorization**. Resumen:\n\n| Endpoints | Scope requerido |\n|-----------|-----------------|\n| `/send/*` (masivo, individual, planificación) | `sms:send` |\n| `/history/list`, `/credit/get` | `sms:read` |\n| `/phone/list`, `/list/list` | `sms:contacts:read` |\n| `/phone/{add,edit,del}`, `/list/{edit,del}`, `/import/upload` | `sms:contacts:write` |\n| `/account/limits` | `account:read` |\n\n> `POST /list/add` (crear una lista) actualmente es accesible con cualquier\n> token válido: aún no está restringido por scope. El rechazo por scope en los endpoints\n> restringidos 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- `/credit/get.json`\n- `/credit/get.xml`\n\nLos nombres de campo en las respuestas están en **PascalCase** (`TotalCredits`, `FirstName`, …),\nmientras que los parámetros de solicitud están en **snake_case** (`id_client`, `address_book_id`, …).\nLos endpoints de lista envuelven sus filas en un array `Items`.\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\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## Coste en créditos de un SMS\n\nUn SMS cuesta **créditos del país × número de partes**.\n\n**Créditos del país** — cada país de destino tiene un precio de 1, 2 o 3 créditos,\nsegún el prefijo internacional del número. El envío a un número cuyo prefijo no\ntarifamos se rechaza con un `400`.\n\n**Número de partes** — un mensaje más largo que un SMS lo divide el operador y\ncada parte se factura. El límite depende de los caracteres utilizados:\n\n| Alfabeto | Mensaje único | Por parte al dividir |\n|----------|---------------|----------------------|\n| GSM-7 (latino estándar) | 160 caracteres | 153 caracteres |\n| Unicode (acentos fuera de GSM-7, cirílico, emoji, …) | 70 caracteres | 67 caracteres |\n\nUn **solo** carácter fuera de GSM-7 pasa **todo** el mensaje a Unicode; así, un\nemoji puede llevar un mensaje de 160 caracteres de 1 a 3 partes. Los caracteres\n`^ { } [ ] ~ | \\` y `€` cuentan como **dos** cada uno, aunque sean GSM-7.\n\n*Ejemplo:* un mensaje de 300 caracteres en latino estándar = 2 partes; enviado a\nun país de 2 créditos, cuesta 2 × 2 = **4 créditos** por destinatario.\n\n## Formato de los números de teléfono\n\nLos números de teléfono se normalizan automáticamente. Puede enviarlos en muchos formatos:\nlos espacios, guiones, puntos, barras, paréntesis, guiones bajos y espacios no separables\nse eliminan antes de la validación. Cualquier otro carácter (letras, apóstrofos,\n`=`, `;`, etc.) invalida el número.\n\n| Válido                                          | No válido                                          |\n|------------------------------------------------|----------------------------------------------------|\n| `+41794849980` — E.164 internacional           | `0612345678` — formato nacional (`0` inicial)      |\n| `0041 79 484 99 80` — prefijo 00 + espacios    | `41'794'849'80` — apóstrofos (no se eliminan)      |\n| `+33 6-12-34-56-78` — + con guiones            | `tel=0041794849980` — caracteres adicionales       |\n| `41794849980` — solo dígitos                   | `1234567` — demasiado corto (< 8 dígitos)          |\n\n**Reglas:**\n- Prefijos aceptados: `+`, `00` o sin prefijo\n- Longitud tras la normalización: **de 8 a 15 dígitos** (máximo E.164)\n- El primer dígito tras eliminar el prefijo debe ser **del 1 al 9** (no `0`)\n- Separadores eliminados: espacio, tabulación, guion `-`, punto `.`, barra `/`, paréntesis `( )`, guion bajo `_`, NBSP\n- Cualquier otra cosa (letras, apóstrofos, `=`, `;`, `+` dentro del número, etc.) → rechazado\n- Forma almacenada en nuestra base de datos: solo dígitos, sin prefijo (p. ej. `41794849980`)\n\n## Códigos de error\n\n| HTTP | Código | Significado |\n|------|--------|-------------|\n| 400  | 103    | Entrada malformada — parámetro obligatorio ausente o no válido |\n| 202  | 202    | Créditos SMS insuficientes |\n| 401  |        | `id_client` / `api_key` no válidos |\n| 500  | 500    | Error interno |\n\n## Webhooks\n\nMailpro™ puede notificar a su servidor en tiempo real cuando se producen eventos SMS en su\ncuenta (un SMS se entrega, un SMS falla, su saldo de créditos es bajo, etc.).\nEstilo 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 sola vez** (estilo Stripe / GitHub): guárdelo.\n2. **Mailpro envía** mediante POST una carga útil JSON firmada a su URL en cuanto un evento coincide.\n3. **Verifique la firma** en el servidor con su `secret` (fragmentos a continuación).\n4. **Responda con 200–299** en menos de 10 segundos. De lo contrario, reintentaremos con\n   backoff exponencial (10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, después se abandona).\n\n> **⏱ Retardo de activación** — tras crear, actualizar o eliminar un webhook, el\n> cambio tarda hasta **10 minutos** en propagarse por todos los servidores de la API\n> de Mailpro. Durante ese intervalo, los eventos pueden no coincidir aún con su nueva suscripción\n> (o pueden seguir coincidiendo con una recién eliminada). Es el tiempo necesario para\n> refrescar la caché de suscripciones en memoria de cada instancia de la API.\n\n### Sobre del payload\n\nTodos los eventos comparten un sobre común:\n\n```json\n{\n  \"id\":         \"evt_8f3a9b2c4d1e5f6789abcdef01234567\",\n  \"type\":       \"sms.queued\",\n  \"created\":    1748194800,\n  \"apiVersion\": \"sms\",\n  \"account\":    { \"id\": 12345, \"name\": \"ACME Corp\" },\n  \"data\":       {\n    \"messageId\":   12345,\n    \"to\":          \"41791234567\",\n    \"queuedAt\":    \"2026-05-27T14:32:12.0123456Z\",\n    \"scheduledAt\": \"2026-05-27T14:32:12.0123456Z\",\n    \"parts\":       1\n  }\n}\n```\n\n| Campo | Formato | Descripción |\n|-------|---------|-------------|\n| `id` | `evt_` + 32 hex | ID único del evento — utilícelo como clave de idempotencia en su lado. |\n| `type` | `<dominio>.<verbo>` | Tipo de evento canónico. |\n| `created` | Segundos Unix UTC | Incluido en la firma HMAC. |\n| `apiVersion` | `\"sms\"` para los eventos emitidos por `POST /sms/send/add_single`; `\"v3\"` para los eventos emitidos por `POST /v3/Sms/SingleSMS`; `\"watcher\"` para los eventos basados en DLR emitidos por el worker. | Qué componente de Mailpro publicó el evento. |\n| `account.id` | int | Su ID de cliente Mailpro (= `id_client`). |\n| `account.name` | string | El nombre de su cuenta (útil para depuración en el cliente). |\n| `data` | object | Carga útil del evento — su forma depende de `type` (véase el catálogo a continuación). |\n\n### Catálogo de eventos\n\nSolo se emiten realmente los eventos enumerados a continuación. Las formas son el JSON literal\nenviado por la plataforma: respete estos nombres de campo exactamente al parsearlos.\n\n| Evento | Disparador | Forma de `data` |\n|--------|------------|-----------------|\n| `ping` | Prueba mediante `POST /webhooks/{id}/test` | `{ message }` |\n| `sms.queued` | `POST /sms/send/add_single` o `POST /v3/Sms/SingleSMS` aceptado en la cola de envío de Mailpro | `{ messageId: int, to: string, queuedAt: ISO-8601, scheduledAt: ISO-8601, parts: int }` |\n| `sms.delivered` | DLR con código de operador `004` u `008` (códigos de éxito) | `{ messageId: int, phone: string, stateCode: string, dlrDate: datetime }` |\n| `sms.failed` | DLR con cualquier otro código de operador (timeout, no entregado, rechazado, en lista negra, …) | `{ messageId: int, phone: string, stateCode: string, dlrDate: datetime }` |\n| `credits.sms.low` | El saldo de créditos SMS ha caído por debajo de su umbral de alerta (worker `CreditsLowWatcher`) | `{ remaining: int, threshold: int, alertedAt: ISO-8601 }` |\n\n> **Nota** — no existe un evento `sms.sent`. El DLR del operador es la única retroalimentación\n> que recibe la plataforma entre «en cola» y «entregado/fallido», por lo que el siguiente\n> evento que recibirá tras `sms.queued` será `sms.delivered` (éxito) o\n> `sms.failed` (error). La mayoría de los mensajes llegan al operador en segundos y se recibe\n> un DLR en minutos; las condiciones de la red móvil pueden, en ocasiones, prolongar este plazo\n> a horas.\n\n> **Nomenclatura de campos** — `sms.queued` utiliza `to` (el destino tal como lo envió\n> el llamador de la API, tras la normalización). `sms.delivered` / `sms.failed` utilizan\n> `phone` (el destino tal como lo devolvió el operador en el DLR). Serán\n> los mismos dígitos en la práctica, pero los nombres difieren porque los eventos\n> proceden de rutas de código distintas.\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: sms.delivered\nX-Mailpro-Attempt:   1\n```\n\nPara verificar:\n1. Extraiga `t` y `v1` de la cabecera.\n2. **Rechace** si `|now - t| > 300` (ventana de protección contra replay 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 | Espera antes del siguiente |\n|---------|----------------------------|\n| 1 → 2 | 10 segundos |\n| 2 → 3 | 1 minuto |\n| 3 → 4 | 5 minutos |\n| 4 → 5 | 30 minutos |\n| 5 → 6 | 2 horas |\n| 6 → 7 | 6 horas |\n| 7 | abandonado (entrega marcada como `failed`) |\n\nTras **10 fallos consecutivos** en el mismo webhook, este se **desactiva\nautomáticamente** (`isActive: false`) y usted recibe un correo de notificación. Reactívelo\ncon `PUT /webhooks/{id}` una vez que su endpoint esté corregido.\n\n### Éxito = HTTP 2xx\n\nConsideramos su webhook como satisfactorio únicamente si devuelve un estado dentro de `200–299`.\nCualquier 3xx/4xx/5xx o un timeout (> 10 s) cuenta como un fallo y dispara reintentos.\nSi su endpoint está caído permanentemente, 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 del payload | 256 KB |\n| Timeout HTTP por intento | 10 segundos |\n| Retención del historial de entregas | 30 días |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/sms",
      "description": "Producción"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token JWT Bearer obtenido mediante `POST /sms/token` (codificación de formulario, grant\n`password`). El mismo token también es válido en la API CRM v3 y en la\nAPI Email v2 — autentíquese una 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": "id_client",
        "description": "Su ID de cliente numérico de Mailpro — transporte **preferido** (cabecera HTTP).\nLas URL son registradas por los servidores web, Cloudflare y los proxies, por lo que las credenciales\nen la cadena de consulta pueden filtrarse en los registros de acceso. Las cabeceras no se registran.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "api_key",
        "description": "Su clave de API (GUID) — transporte **preferido** (cabecera HTTP).\n"
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "id_client",
        "description": "Su ID de cliente numérico de Mailpro — **heredado**, mantenido por compatibilidad con versiones anteriores.\nCambie a la cabecera `id_client` cuando pueda.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "Su clave de API (GUID) — **heredada**, mantenida por compatibilidad con versiones anteriores.\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": "header",
        "required": false,
        "description": "Elementos por página — 5000 por defecto y como máximo (véase Paginación). Cabecera HTTP o parámetro de query.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5000,
          "default": 5000
        },
        "example": 100
      },
      "pageNumber": {
        "name": "PageNumber",
        "in": "header",
        "required": false,
        "description": "Número de página (basado en 1) para las respuestas paginadas. Se envía como cabecera HTTP.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      },
      "sortByName": {
        "name": "SortByName",
        "in": "header",
        "required": false,
        "description": "Establézcalo en `true` para ordenar los resultados alfabéticamente por nombre.",
        "schema": {
          "type": "boolean",
          "default": false
        }
      }
    },
    "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": "Duración 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 necesidad de volver a autenticarse"
          },
          "application": {
            "type": "string",
            "description": "Nombre de la integración (solo para grants de terceros)",
            "nullable": true
          }
        }
      },
      "PhoneList": {
        "type": "object",
        "properties": {
          "AddressBookId": {
            "type": "integer",
            "description": "Unique identifier of the phone list",
            "example": 42
          },
          "Name": {
            "type": "string",
            "description": "Nombre visible de la lista de teléfonos",
            "example": "Newsletter subscribers"
          },
          "TotalNumberPhones": {
            "type": "integer",
            "description": "Number of phone numbers in this list",
            "example": 1547
          }
        }
      },
      "PhoneNumber": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificador único de la entrada del número de teléfono",
            "example": 1001
          },
          "Number": {
            "type": "string",
            "description": "Número de teléfono en formato internacional simple (forma almacenada — consulte «Formato del número de teléfono» en la descripción de la API para conocer los formatos de entrada aceptados)",
            "example": "41791234567"
          },
          "FirstName": {
            "type": "string",
            "description": "Nombre del contacto",
            "example": "Alice"
          },
          "LastName": {
            "type": "string",
            "description": "Apellido del contacto",
            "example": "Dupont"
          }
        }
      },
      "SingleSend": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificador único del envío creado",
            "example": 5001
          },
          "Message": {
            "type": "string",
            "description": "El texto del mensaje SMS",
            "example": "Your verification code is 8472"
          },
          "ScheduledTime": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha en la que el SMS será (o fue) enviado",
            "example": "2026-04-15T09:00:00"
          },
          "To": {
            "type": "string",
            "description": "Número de teléfono del destinatario",
            "example": "0041791234567"
          },
          "Charge": {
            "type": "string",
            "description": "Créditos realmente facturados por este envío = **créditos del país × número de partes**.\nP. ej., un SMS de 1 parte a Panamá (+507, 3 créditos/SMS) → `\"3\"`; un SMS de 2 partes → `\"6\"`.\n",
            "example": "3"
          },
          "Parts": {
            "type": "integer",
            "description": "Número de segmentos SMS (partes GSM 03.38) en los que se dividió el mensaje.",
            "example": 1
          }
        }
      },
      "BulkSend": {
        "type": "object",
        "properties": {
          "Id": {
            "type": "integer",
            "description": "Identificador único del envío masivo creado",
            "example": 6001
          },
          "Message": {
            "type": "string",
            "description": "El texto del mensaje SMS",
            "example": "Spring sale — 20% off all products this weekend!"
          },
          "ScheduledTime": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha en la que la campaña de SMS será (o fue) enviada",
            "example": "2026-04-20T10:00:00"
          },
          "To": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Lista de ID de las listas a las que va dirigido este envío",
            "example": [
              "42"
            ]
          },
          "Charge": {
            "type": "string",
            "description": "Total de créditos facturados por el envío completo = **Σ (créditos del país × partes)**\nsobre todos los números de la lista.\n",
            "example": "150"
          },
          "Parts": {
            "type": "integer",
            "description": "Número de segmentos SMS (partes GSM 03.38) por mensaje.",
            "example": 1
          }
        }
      },
      "CreditBalance": {
        "type": "object",
        "properties": {
          "TotalCredits": {
            "type": "number",
            "description": "Saldo de créditos SMS restante (créditos del plan + créditos mensuales).\n\nEs un recuento de créditos, no un número de mensajes: un SMS cuesta\n`créditos del país × número de partes` — véase «Coste en créditos de un SMS» en la\ndescripción de la API.\n",
            "example": 5000
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "Error": {
            "type": "string",
            "description": "Mensaje de error legible por humanos",
            "example": "Malformed Input"
          },
          "Code": {
            "type": "integer",
            "description": "Código de error específico de Mailpro",
            "example": 103
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://example.com/hooks/mailpro"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Slack integration"
          },
          "is_active": {
            "type": "boolean",
            "description": "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
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipos de eventos suscritos. Un array vacío significa todos los eventos de esta API.",
            "example": [
              "sms.delivered",
              "sms.failed"
            ]
          }
        }
      },
      "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 evento a los que suscribirse (consulte el catálogo anterior). Utilice `[\"*\"]` para suscribirse a todos los eventos de esta API.",
            "example": [
              "sms.delivered",
              "sms.failed"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 500,
            "example": "Slack integration"
          }
        }
      },
      "WebhookCreateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "Secreto HMAC. **Se muestra aquí una sola vez, nunca más.** Almacénelo en el lado del 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": "Establézcalo en `true` para volver a habilitar 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": "sms.delivered"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "retrying",
              "failed"
            ]
          },
          "statusCode": {
            "type": "integer",
            "nullable": true,
            "example": 200
          },
          "responseTimeMs": {
            "type": "integer",
            "nullable": true,
            "example": 142
          },
          "attemptCount": {
            "type": "integer"
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "nextAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Authentication",
      "description": "Obtenga un token JWT Bearer para autenticar todas las demás llamadas a la API. El endpoint\nSMS `/token` es una redirección 307 al emisor canónico `/v3/token` —\nsu cliente HTTP sigue la redirección de forma transparente (se conservan el método POST\ny el cuerpo).\n"
    },
    {
      "name": "Account",
      "description": "Compruebe su saldo de créditos SMS, su cuota mensual de API y el estado de su cuenta."
    },
    {
      "name": "Send SMS",
      "description": "Envíe mensajes SMS — ya sea un **único SMS transaccional** a un destinatario,\no una **campaña masiva** a toda una lista de contactos.\n"
    },
    {
      "name": "Lists",
      "description": "Gestione listas de contactos SMS. Una lista de contactos agrupa números de teléfono para envíos masivos.\nPuede crear hasta 1000 listas por cuenta (mismo límite en las tres API de Mailpro y en la app).\n"
    },
    {
      "name": "Phone Numbers",
      "description": "Gestione números de teléfono individuales dentro de una lista de contactos — añada, actualice y elimine entradas."
    },
    {
      "name": "Credit",
      "description": "Compruebe el saldo restante de créditos SMS de su cuenta (independiente de la cuota mensual de solicitudes de la API — consulte `/account/limits`)."
    },
    {
      "name": "History",
      "description": "Consulte el registro completo de las campañas SMS pasadas."
    },
    {
      "name": "Import",
      "description": "Cargue un archivo CSV o XLSX para importar números de teléfono a una lista de contactos de forma masiva.\nEl archivo se pone en cola para procesarse de manera asíncrona — realice el seguimiento de la finalización mediante\nel `ImportJobId` devuelto o mediante el callback opcional `webhook_url`.\n"
    },
    {
      "name": "Webhooks",
      "description": "Suscriba su servidor a notificaciones en tiempo real de eventos SMS. Mailpro envía mediante POST\nuna carga útil 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, los fragmentos de verificación de firma y la política de reintentos.\n"
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getSmsAccessToken",
        "summary": "Obtener token de acceso (redirección 307 a /v3/token)",
        "security": [],
        "description": "Obtiene un token JWT Bearer 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 API CRM v3 y en\nla API Email v2.\n\n> **⚙ Detalle de implementación** — `POST /sms/token` es una **redirección\n> temporal 307** a `POST /v3/token` (configurada en la capa de reescritura\n> del `web.config` de IIS). HTTP 307 conserva tanto el **método** (`POST`)\n> como el **cuerpo de la solicitud**, por lo que cualquier cliente HTTP conforme\n> a la norma sigue la redirección de forma transparente — usted sigue haciendo POST a `/sms/token`\n> y recibe un JWT válido. No hay lógica de emisión de tokens duplicada; la API\n> SMS nunca emite tokens por sí misma.\n\n### Tipos de grant admitidos\n| Tipo de grant | Caso de uso |\n|---------------|-------------|\n| `password` | Integración estándar — nombre de usuario + clave de API |\n| `refresh_token` | Renovar un token de acceso a punto de caducar sin volver a autenticarse |\n| `client_credentials` | Servidor a servidor solo con el ID de cliente |\n\n### Duración del token\n- Token de acceso: **30 días**\n- Refresh token: **90 días**\n\nUtilice `grant_type=refresh_token` para renovar el token de acceso sin\nvolver a autenticarse. Almacene los tokens en el lado del servidor (Vault, variables de entorno);\nnunca los incruste en JS de navegador ni en binarios de aplicaciones móviles. Consulte la\nnota de seguridad completa en la documentación de `/token` de la API CRM v3.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "password",
                      "refresh_token",
                      "client_credentials"
                    ],
                    "example": "password"
                  },
                  "username": {
                    "type": "string",
                    "description": "Su nombre de usuario de Mailpro (correo electrónico). Obligatorio para el grant `password`.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "Su clave de API de Mailpro (formato GUID). Obligatorio para el grant `password`.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Refresh token anterior. Obligatorio para el grant `refresh_token`."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Su ID de cliente de Mailpro (entero). Obligatorio para el grant `client_credentials`.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token emitido correctamente. Devuelto por `POST /v3/token` tras el\nseguimiento transparente del 307 — su cliente HTTP ve un 200 normal con\nla misma estructura de cuerpo que recibiría directamente del endpoint\nde 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 reescritura\nde IIS en `web.config`. Los clientes HTTP conformes a la norma la siguen\nautomáticamente y conservan el método POST original junto con el cuerpo del formulario.\nSolo es visible para los clientes que 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 grant no admitido",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Credenciales incorrectas",
                    "value": {
                      "error": "invalid_grant",
                      "error_description": "The username or password is incorrect."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/credit/get.{format}": {
      "get": {
        "tags": [
          "Credit"
        ],
        "operationId": "getSmsCredits",
        "security": [
          {
            "OAuth2": [
              "sms:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtener el saldo de créditos SMS",
        "description": "Devuelve el saldo actual de créditos SMS de su cuenta.\nLos créditos SMS se consumen en el momento del envío. Un SMS estándar (≤160 caracteres GSM-7)\ncuesta 1 crédito. Los mensajes más largos o los que contengan caracteres especiales pueden costar más.\n\n> Nota: esto devuelve su **saldo de créditos de envío de SMS**, no su cuota de solicitudes de la API.\n> Para la cuota de la API consulte `GET /account/limits.{format}`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo de créditos devuelto correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalance"
                },
                "example": {
                  "TotalCredits": 5000
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/account/limits.{format}": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getSmsAccountLimits",
        "security": [
          {
            "OAuth2": [
              "account:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Obtener la cuota mensual de la API",
        "description": "Devuelve la cuota mensual de solicitudes de la API para el cliente autenticado.\n\n**Cálculo de la cuota:** el límite se calibra a partir de los créditos de\nla suscripción de correo electrónico (normalmente `subscription_credits × 5`). Para\nun plan de 10 000 correos electrónicos al mes, esto da un presupuesto mensual\nde 50 000 solicitudes. Se restablece en la **fecha de aniversario de la suscripción**\n(no el día 1 del mes natural).\n\n**Qué consume créditos:**\n- Cada solicitud autenticada a la API en los endpoints `v2`, `v3` o `sms`.\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 una suscripción correspondiente.\n\nLa cuota se **comparte entre las 3 APIs de Mailpro** (`v2`, `v3`, `sms`)\n— un cliente = un presupuesto mensual para toda la plataforma. Los envíos SMS\nconsumen adicionalmente el saldo dedicado de créditos SMS\n(`GET /credit/get.{format}`).\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": null
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "404": {
            "description": "No se encontró registro de cuota (cuenta recién creada; la fila se creará en la primera solicitud autenticada)."
          }
        }
      }
    },
    "/history/list.{format}": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "listSmsHistory",
        "security": [
          {
            "OAuth2": [
              "sms:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar el historial de envíos de SMS",
        "description": "Devuelve un registro paginado de todas las campañas SMS pasadas enviadas desde esta cuenta.\nLos resultados se ordenan por fecha descendente (los más recientes primero).\nPaginación: `NumberOfRecords` y `PageNumber` (cabeceras o query, 5000 por página por defecto).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de historial devuelta correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "Id": {
                            "type": "integer",
                            "description": "Identificador del envío al que pertenece esta fila",
                            "example": 583294
                          },
                          "DateSent": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Marca de tiempo de entrega informada por el operador",
                            "example": "2026-07-17T18:56:39.813"
                          },
                          "Message": {
                            "type": "string",
                            "example": "Your verification code is 8472"
                          },
                          "Charge": {
                            "type": "number",
                            "description": "Créditos facturados por esta fila = **créditos del país × número de partes**\n(p. ej., 3 para un SMS de 1 parte a Panamá). Antes siempre `1`.\n",
                            "example": 3
                          },
                          "Parts": {
                            "type": "integer",
                            "description": "Número de segmentos SMS (partes GSM 03.38) en los que se dividió el mensaje.",
                            "example": 1
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "Items": [
                    {
                      "Id": 583294,
                      "DateSent": "2026-07-17T18:56:39.813",
                      "Message": "Your verification code is 8472",
                      "Charge": 3,
                      "Parts": 1
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/list/list.{format}": {
      "get": {
        "tags": [
          "Lists"
        ],
        "operationId": "listSmsLists",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar las listas de contactos telefónicos",
        "description": "Devuelve todas las listas de contactos SMS de la cuenta.\nUtilice los valores `Id` devueltos al enviar campañas SMS masivas o al añadir números de teléfono.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "responses": {
          "200": {
            "description": "Listas de teléfonos devueltas correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PhoneList"
                      }
                    }
                  }
                },
                "example": {
                  "Items": [
                    {
                      "AddressBookId": 42,
                      "Name": "Newsletter subscribers",
                      "TotalNumberPhones": 1547
                    },
                    {
                      "AddressBookId": 43,
                      "Name": "Loyalty program",
                      "TotalNumberPhones": 823
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/list/add.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "addSmsList",
        "summary": "Crear una lista de contactos",
        "description": "Crea una nueva lista de contactos SMS con el nombre indicado.\nLa lista comienza vacía — añada números de teléfono con `POST /phone/add`.\nMáximo 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",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "name"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "name": {
                    "type": "string",
                    "description": "Nombre visible de la nueva lista de contactos",
                    "example": "Spring campaign 2026"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista de contactos creada correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneList"
                },
                "example": {
                  "Id": 44,
                  "Name": "Spring campaign 2026",
                  "NumberPhones": 0
                }
              }
            }
          },
          "400": {
            "description": "Falta el campo obligatorio (name)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/list/edit.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "editSmsList",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Renombrar una lista de contactos",
        "description": "Actualiza el nombre visible de una lista de contactos SMS existente.\nLos números de teléfono de la lista no se ven afectados.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "address_book_id",
                  "name"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID de la lista de contactos a renombrar (de `/list/list`)",
                    "example": 42
                  },
                  "name": {
                    "type": "string",
                    "description": "Nuevo nombre visible para la lista de contactos",
                    "example": "Spring campaign 2026 — updated"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista de contactos renombrada correctamente"
          },
          "400": {
            "description": "Falta el campo obligatorio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/list/del.{format}": {
      "post": {
        "tags": [
          "Lists"
        ],
        "operationId": "deleteSmsList",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar una lista de contactos",
        "description": "Elimina de forma permanente una lista de contactos SMS **y todos los números de teléfono que contiene**.\nEsta acción no se puede deshacer.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "address_book_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID de la lista de contactos que se va a eliminar",
                    "example": 42
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista de contactos eliminada correctamente"
          },
          "400": {
            "description": "Falta address_book_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/phone/list.{format}": {
      "get": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "listPhones",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar los números de teléfono de una lista de contactos",
        "description": "Devuelve una lista paginada de los números de teléfono de una lista de contactos concreta.\nUtilice `address_book_id` para especificar qué lista desea recuperar.\nPaginación: `NumberOfRecords` y `PageNumber` (5000 por página por defecto, página 1).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "address_book_id",
            "in": "query",
            "required": true,
            "description": "ID de la lista de contactos de la que se van a recuperar los números de teléfono",
            "schema": {
              "type": "integer"
            },
            "example": 42
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          },
          {
            "$ref": "#/components/parameters/sortByName"
          }
        ],
        "responses": {
          "200": {
            "description": "Números de teléfono devueltos correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PhoneNumber"
                      }
                    }
                  }
                },
                "example": {
                  "Items": [
                    {
                      "Id": 1001,
                      "Number": "41791234567",
                      "FirstName": "Alice",
                      "LastName": "Dupont"
                    },
                    {
                      "Id": 1002,
                      "Number": "33612345678",
                      "FirstName": "Bob",
                      "LastName": "Martin"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/phone/add.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "addPhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Añadir uno o varios números de teléfono a una lista",
        "description": "Añade uno o varios números de teléfono a una lista de contactos.\n\n**Número único:** utilice el campo `number`.\n\n**Importación masiva:** utilice el campo `phone_list` con los números separados por punto y coma:\n`+41791234567;+33612345678;0049301234567`\n\nLos números de teléfono aceptan los formatos `+`, `00` o simple — consulte la **Formato del número de teléfono**\nen la descripción de la API para ver la lista completa de entradas aceptadas y rechazadas.\nLos números duplicados se omiten silenciosamente salvo que se establezca `force=1`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "address_book_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "address_book_id": {
                    "type": "integer",
                    "description": "ID de la lista de contactos a la que añadir el o los números",
                    "example": 42
                  },
                  "number": {
                    "type": "string",
                    "description": "Número de teléfono único. Acepta `+41…`, `0041…` o `41…` con o sin\nseparadores (espacios, guiones, puntos, barras, paréntesis). Consulte\n**Formato del número de teléfono** en la descripción de la API.\nUtilice este campo **O** `phone_list` — no ambos.\n",
                    "example": "+41791234567"
                  },
                  "phone_list": {
                    "type": "string",
                    "description": "Lista de números de teléfono separados por punto y coma para la importación masiva.\nUtilice este campo **O** `number` — no ambos.\nEjemplo: `0041791234567;0033612345678`\n",
                    "example": "0041791234567;0033612345678;0049301234567"
                  },
                  "firstname": {
                    "type": "string",
                    "description": "Nombre del contacto (opcional, solo para número único)",
                    "example": "Alice"
                  },
                  "lastname": {
                    "type": "string",
                    "description": "Apellido del contacto (opcional, solo para número único)",
                    "example": "Dupont"
                  },
                  "force": {
                    "type": "integer",
                    "description": "Establézcalo en `1` para añadir un número aunque se haya dado de baja previamente o ya exista.\nValor por defecto: `0` (los duplicados se omiten).\n",
                    "enum": [
                      0,
                      1
                    ],
                    "default": 0,
                    "example": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Número(s) de teléfono añadido(s) correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                },
                "example": {
                  "Id": 1003,
                  "Number": "0041791234567",
                  "FirstName": "Alice",
                  "LastName": "Dupont"
                }
              }
            }
          },
          "400": {
            "description": "Falta el campo obligatorio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/phone/edit.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "editPhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Actualizar una entrada de número de teléfono",
        "description": "Actualiza el número de teléfono o los datos de contacto de una entrada existente.\nUtilice `number_id` (de `/phone/list`) para identificar la entrada que se va a actualizar.\nSolo se actualizan los campos proporcionados en la solicitud.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "number_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "number_id": {
                    "type": "integer",
                    "description": "ID de la entrada del número de teléfono que se va a actualizar (de `/phone/list`)",
                    "example": 1001
                  },
                  "number": {
                    "type": "string",
                    "description": "Nuevo número de teléfono. Acepta `+41…`, `0041…` o `41…` con o sin separadores. Consulte **Formato del número de teléfono** en la descripción de la API.",
                    "example": "+41791234568"
                  },
                  "firstname": {
                    "type": "string",
                    "description": "Nuevo nombre del contacto",
                    "example": "Alice"
                  },
                  "lastname": {
                    "type": "string",
                    "description": "Nuevo apellido del contacto",
                    "example": "Dupont-Martin"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Entrada del número de teléfono actualizada correctamente"
          },
          "400": {
            "description": "Falta number_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/phone/del.{format}": {
      "post": {
        "tags": [
          "Phone Numbers"
        ],
        "operationId": "deletePhone",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Eliminar un número de teléfono de una lista",
        "description": "Elimina permanentemente una entrada de número de teléfono concreta de su lista de contactos.\nUtilice `number_id` (de `/phone/list`) para identificar la entrada.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "number_id"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "number_id": {
                    "type": "integer",
                    "description": "ID de la entrada del número de teléfono que se va a eliminar (de `/phone/list`)",
                    "example": 1001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Número de teléfono eliminado correctamente"
          },
          "400": {
            "description": "Falta number_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/add.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendBulkSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar SMS masivos a una lista de contactos",
        "description": "Envía un mensaje SMS a **todos los números de teléfono** de una lista de contactos.\nAdmite la programación: establezca `scheduled_time` en una fecha futura para enviar más tarde,\no omítalo para enviar de inmediato.\n\n**Consumo de créditos:** los créditos se descuentan en el momento del envío.\nLos mensajes largos (>160 caracteres GSM-7) se dividen en varias partes,\ncada una con un coste adicional en créditos.\n\nLa respuesta devuelve `{ \"Error\": \"Insufficient Credit\", \"Code\": 202 }` si\nla cuenta no tiene créditos suficientes.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "message",
                  "to"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "message": {
                    "type": "string",
                    "description": "Texto del mensaje SMS. Manténgalo por debajo de 160 caracteres para un SMS de una sola parte.\nLos caracteres que no pertenecen al alfabeto GSM-7 (p. ej., chino, árabe, emojis)\ncambian la codificación a Unicode, reduciendo el límite a 70 caracteres por parte.\n",
                    "example": "Flash sale today only — 30% off all orders. Shop now at mailpro.com/shop"
                  },
                  "to": {
                    "type": "integer",
                    "description": "ID de la lista de contactos a la que enviar (de `/list/list`)",
                    "example": 42
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Programe el envío para una fecha/hora futura (ISO 8601).\nOmita o deje vacío para enviar de inmediato.\n",
                    "example": "2026-04-20T10:00:00"
                  },
                  "shorten_urls": {
                    "type": "boolean",
                    "default": false,
                    "description": "Indique `true` para sustituir cada enlace del mensaje por un enlace corto `https://mailp.ro/m/...`: menos caracteres, por lo que a veces menos partes de SMS facturadas. Un enlace que no se pueda acortar se queda como está."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envío masivo de SMS creado correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkSend"
                },
                "example": {
                  "Id": 6001,
                  "Message": "Flash sale today only — 30% off all orders. Shop now at mailpro.com/shop",
                  "ScheduledTime": "2026-04-20T10:00:00",
                  "To": [
                    "42"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Créditos SMS insuficientes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Insufficient Credit",
                  "Code": 202
                }
              }
            }
          },
          "400": {
            "description": "Falta el campo obligatorio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/add_single.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendSingleSmsGet",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar un único SMS (GET)",
        "description": "Envía un único SMS a un destinatario mediante una solicitud GET.\nÚtil para integraciones sencillas donde POST no esté disponible.\nLas credenciales y el mensaje se pasan como parámetros de consulta.\n\n**Nota:** evite usar GET para mensajes sensibles — los parámetros de consulta aparecen en los registros del servidor.\nUtilice preferentemente `POST /send/add_single`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Número de teléfono del destinatario. Acepta `+41…`, `0041…` o `41…` con o sin separadores. Consulte **Formato del número de teléfono** en la descripción de la API.",
            "schema": {
              "type": "string"
            },
            "example": "+41791234567"
          },
          {
            "name": "message",
            "in": "query",
            "required": true,
            "description": "Texto del mensaje SMS (máx. 160 caracteres para la codificación estándar)",
            "schema": {
              "type": "string"
            },
            "example": "Your appointment is confirmed for tomorrow at 10:00."
          },
          {
            "name": "scheduled_time",
            "in": "query",
            "description": "Programe el envío (ISO 8601). Omita para enviar de inmediato.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "shorten_urls",
            "in": "query",
            "description": "Indique `true` para sustituir cada enlace del mensaje por un enlace corto `https://mailp.ro/m/...`: menos caracteres, por lo que a veces menos partes de SMS facturadas. Un enlace que no se pueda acortar se queda como está.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SMS enviado (o programado) correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SingleSend"
                },
                "example": {
                  "Id": 5001,
                  "Message": "Your appointment is confirmed for tomorrow at 10:00.",
                  "ScheduledTime": "2026-04-15T09:00:00",
                  "To": "0041791234567",
                  "Charge": "1"
                }
              }
            }
          },
          "202": {
            "description": "Créditos SMS insuficientes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "400": {
            "description": "Falta el parámetro obligatorio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      },
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "sendSingleSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Enviar un único SMS",
        "description": "Envía un único mensaje SMS a un número de teléfono destinatario.\nAdmite programación mediante `scheduled_time`.\n\n**Consumo de créditos:** los créditos se descuentan en el momento del envío.\nEl campo `Charge` de la respuesta muestra cuántos créditos se consumieron.\n\nLa respuesta devuelve `{ \"Error\": \"Insufficient Credit\", \"Code\": 202 }` si\nla cuenta no tiene créditos suficientes.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key",
                  "message",
                  "to"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "message": {
                    "type": "string",
                    "description": "Texto del mensaje SMS",
                    "example": "Your verification code is 8472. Valid for 10 minutes."
                  },
                  "to": {
                    "type": "string",
                    "description": "Número de teléfono del destinatario. Acepta `+41…`, `0041…` o `41…` con o sin separadores. Consulte **Formato del número de teléfono** en la descripción de la API.",
                    "example": "+41791234567"
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Programe el envío para una hora futura. Omita para enviar de inmediato.",
                    "example": "2026-04-15T14:30:00"
                  },
                  "shorten_urls": {
                    "type": "boolean",
                    "default": false,
                    "description": "Indique `true` para sustituir cada enlace del mensaje por un enlace corto `https://mailp.ro/m/...`: menos caracteres, por lo que a veces menos partes de SMS facturadas. Un enlace que no se pueda acortar se queda como está."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS enviado (o programado) correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SingleSend"
                },
                "example": {
                  "Id": 5001,
                  "Message": "Your verification code is 8472. Valid for 10 minutes.",
                  "ScheduledTime": "2026-04-15T14:30:00",
                  "To": "0041791234567",
                  "Charge": "1"
                }
              }
            }
          },
          "202": {
            "description": "Créditos SMS insuficientes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Insufficient Credit",
                  "Code": 202
                }
              }
            }
          },
          "400": {
            "description": "Falta el campo obligatorio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Malformed Input",
                  "Code": 103
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/list.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "listSmsSends",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar las campañas SMS",
        "description": "Devuelve la lista de campañas SMS (envíos masivos) de la cuenta.\nPaginación mediante las cabeceras `NumberOfRecords` y `PageNumber`.\n\nUtilice `type_to` para filtrar por tipo de envío:\n- `0` (por defecto) — envíos masivos a listas\n- `1` — envíos individuales únicos\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "type_to",
            "in": "query",
            "description": "Filtro de tipo de envío:\n- `0` (por defecto) — envíos masivos a una lista de contactos\n- `1` — envíos individuales a un solo número\n",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de campañas SMS devuelta correctamente",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SingleSend"
                  }
                },
                "example": [
                  {
                    "Id": 5001,
                    "Message": "Your verification code is 8472",
                    "ScheduledTime": "2026-04-15T09:00:00",
                    "To": "41791234567"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/del.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "deleteSmsSend",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar o eliminar un envío de SMS",
        "description": "Cancela un envío SMS **programado pendiente**, o elimina uno **completado** del historial.\nSolo se pueden cancelar los envíos programados para el futuro. 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": [
                  "id_client",
                  "api_key",
                  "id_send"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "description": "Su ID de cliente de Mailpro",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "description": "Su clave de API (GUID)",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "id_send": {
                    "type": "integer",
                    "description": "ID del envío SMS que se va a cancelar o eliminar (de `/send/list`)",
                    "example": 6001
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envío SMS cancelado o eliminado correctamente",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK"
                }
              }
            }
          },
          "400": {
            "description": "Falta id_send",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "500": {
            "description": "Eliminación fallida (envío no encontrado o ya procesado)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": "Delete failed",
                  "Code": 500
                }
              }
            }
          }
        }
      }
    },
    "/send/scheduled.{format}": {
      "get": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "listScheduledSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Listar mis envíos SMS programados",
        "description": "Devuelve los envíos SMS (únicos o de campaña) programados para una fecha futura que\naún no se han despachado. Útil antes de llamar a `/cancel` o `/reschedule`.\n\nLos registros se ordenan por `scheduled_time` ascendente.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "id_client",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 12345
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
          },
          {
            "$ref": "#/components/parameters/numberOfRecords"
          },
          {
            "$ref": "#/components/parameters/pageNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de envíos SMS programados",
            "content": {
              "application/json": {
                "example": [
                  {
                    "Id": 9001,
                    "Message": "Black Friday: 30% off until midnight.",
                    "ScheduledTime": "2026-11-27T12:00:00",
                    "To": "+33671234567"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/send/{id_send}/cancel.{format}": {
      "post": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "cancelScheduledSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cancelar un envío SMS programado",
        "description": "Cancela un SMS programado que aún no se ha despachado. Si el envío ya\nse ha procesado (o no existe / pertenece a otro cliente),\ndevuelve **409 Conflict**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "id_send",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 9001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key"
                ],
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "example": "a1b2c3d4-..."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envío cancelado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Cancelled": 9001
                }
              }
            }
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "409": {
            "description": "Ya despachado o no encontrado",
            "content": {
              "application/json": {
                "example": {
                  "error": "conflict",
                  "message": "Send not found, not owned by client, or already dispatched."
                }
              }
            }
          }
        }
      }
    },
    "/send/{id_send}/reschedule.{format}": {
      "patch": {
        "tags": [
          "Send SMS"
        ],
        "operationId": "rescheduleSms",
        "security": [
          {
            "OAuth2": [
              "sms:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Reprogramar un envío SMS programado",
        "description": "Actualiza la fecha prevista de un SMS programado que aún no se ha despachado.\nLa nueva fecha debe ser **futura** y **dentro de los 90 días**.\n\n**Nombre del campo de fecha:** la API acepta `scheduled_time` (principal) así como\nlos alias heredados `PlanDate`, `date_planned` y `DatePlanned`. Proporcione\ncualquiera de ellos — se utiliza el primero que no sea nulo.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/format"
          },
          {
            "name": "id_send",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 9001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "id_client",
                  "api_key"
                ],
                "description": "Proporcione uno de los siguientes: `scheduled_time`, `PlanDate`, `date_planned` o `DatePlanned`.",
                "properties": {
                  "id_client": {
                    "type": "integer",
                    "example": 12345
                  },
                  "api_key": {
                    "type": "string",
                    "example": "a1b2c3d4-..."
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Nombre de campo principal.",
                    "example": "2026-12-31T14:30:00"
                  },
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias heredado aceptado por compatibilidad con versiones anteriores."
                  },
                  "date_planned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias heredado aceptado por compatibilidad con versiones anteriores."
                  },
                  "DatePlanned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Alias heredado aceptado por compatibilidad con versiones anteriores."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envío reprogramado",
            "content": {
              "application/json": {
                "example": {
                  "Result": "OK",
                  "Id": 9001,
                  "NewScheduledTime": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "scheduled_time ausente o no válido"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "409": {
            "description": "Ya despachado, no encontrado o nueva fecha fuera de rango",
            "content": {
              "application/json": {
                "example": {
                  "error": "conflict",
                  "message": "Reschedule failed — send not found, already dispatched, or new date out of range."
                }
              }
            }
          }
        }
      }
    },
    "/import/upload.{format}": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "security": [
          {
            "OAuth2": [
              "sms:contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Cargar un archivo de números de teléfono (CSV / XLSX) para importación masiva",
        "description": "Cargue un archivo CSV o XLSX para importar números de teléfono a una lista de contactos.\nEl archivo se almacena y se pone en cola para procesarse de manera asíncrona — el endpoint\ndevuelve inmediatamente un `ImportJobId`.\n\n**Tipo de solicitud:** `multipart/form-data`\n\n**Campos de formulario obligatorios:**\n- `id_client` (entero) — su ID de cliente de Mailpro\n- `api_key` (cadena) — su clave de API\n- `id_list` (entero) — ID de la lista de contactos de destino\n- `file` (binario) — el archivo CSV o XLSX que se va a cargar\n\n**Opcional:**\n- `webhook_url` (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 `Phone` o `PhoneNumber` — sin distinción entre mayúsculas y minúsculas)\n- Números en formato internacional (E.164), p. ej., `+41791234567`\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": [
                  "id_list",
                  "file"
                ],
                "properties": {
                  "id_list": {
                    "type": "integer",
                    "format": "int64",
                    "description": "ID de la lista de contactos de destino",
                    "example": 11088
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Archivo CSV o XLSX (UTF-8, máx. 50 MB)"
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL de callback 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": 15,
                  "InternalName": "230575-20260420142616-phones.csv"
                }
              }
            }
          },
          "400": {
            "description": "No se ha cargado ningún archivo o falta id_list"
          },
          "401": {
            "description": "Credenciales no válidas"
          },
          "500": {
            "description": "Error del servidor o del almacenamiento"
          }
        }
      }
    },
    "/webhooks": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "description": "Servicio de gestión de webhooks (independiente 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": [
                        "sms.delivered",
                        "sms.failed"
                      ]
                    }
                  ],
                  "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\nse **muestra una sola vez** — almacénelo inmediatamente en el lado del servidor. Utilícelo para\nverificar la firma HMAC de cada carga útil entrante.\n\n**Límites**: máx. 20 webhooks por cuenta, máx. 50 eventos por webhook.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              },
              "example": {
                "url": "https://example.com/hooks/mailpro",
                "events": [
                  "sms.delivered",
                  "sms.failed"
                ],
                "description": "Integración con Slack"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook creado — el `secret` se devuelve únicamente aquí",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "sms.delivered",
                    "sms.failed"
                  ],
                  "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 no válida, lista de eventos no válida o límite superado"
          },
          "401": {
            "description": "Credenciales no válidas"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/sms",
          "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/sms",
          "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": "Pone en cola un evento `ping` inmediato (o cualquier otro tipo de evento mediante el\ncampo `eventType` del cuerpo) hacia su endpoint. Útil para comprobar la accesibilidad\ny la verificación de firma 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 despacho",
            "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/sms",
          "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 anterior de inmediato.\nEl nuevo secreto se devuelve **una sola vez** en la respuesta — almacénelo. Cada\nentrega a partir de ese momento se firmará con el nuevo secreto.\n\nUtilícelo si sospecha que su secreto se ha visto 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/sms",
          "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 los intentos de entrega",
        "description": "Devuelve el historial de intentos de despacho de este webhook (retención de 30 días).\nÚtil para la depuración — qué eventos se enviaron, los códigos de estado recibidos,\nlos recuentos de reintentos y los mensajes de error.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Matriz de intentos de entrega (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/sms",
          "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": "Reproducir una entrega",
        "description": "Pone en cola un nuevo intento de entrega con la misma carga útil que la original.\nÚtil para volver a activar una entrega fallida tras corregir su endpoint.\nSe crea una NUEVA fila `Webhook_Delivery` (la original se conserva\npara auditoría). La reproducción sigue la política de reintentos estándar\n(mismo calendario de backoff, misma regla de desactivación automática tras 10 fallos).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Reproducción puesta en cola",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook o entrega no encontrado"
          }
        }
      }
    }
  }
}