{
  "openapi": "3.0.3",
  "info": {
    "title": "Integracorp API",
    "version": "1.0.0",
    "description": "API REST de Integracorp para salud operativa, métricas, comunicaciones y el Portal del Paciente. Las rutas se agrupan según el mecanismo de autenticación requerido."
  },
  "servers": [{ "url": "/" }],
  "tags": [
    { "name": "Salud", "description": "Disponibilidad de la API y la base de datos." },
    { "name": "Documentación", "description": "Catálogos de documentación disponibles." },
    { "name": "Métricas", "description": "Indicadores de corretaje, cotizaciones y afiliaciones." },
    { "name": "Correos", "description": "Envío de campañas de correo electrónico." },
    { "name": "Mensajería", "description": "Estado y envíos de WhatsApp." },
    { "name": "Recursos", "description": "Listados operativos paginados." },
    { "name": "Portal Paciente", "description": "Autenticación y funciones privadas del paciente." }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": ["Salud"],
        "summary": "Estado de la API",
        "description": "Comprueba que el servicio HTTP está disponible.",
        "responses": { "200": { "$ref": "#/components/responses/Success" } }
      }
    },
    "/api/health/db": {
      "get": {
        "tags": ["Salud"],
        "summary": "Estado de la base de datos",
        "description": "Comprueba la conectividad con MySQL.",
        "responses": { "200": { "$ref": "#/components/responses/Success" } }
      }
    },
    "/api/auth/login": {
      "post": {
        "tags": ["Portal Paciente"],
        "summary": "Iniciar sesión",
        "description": "Autentica a un paciente con nro_identificacion + password (patient_portal_password en texto plano). Requiere patient_portal_authorized=1. Devuelve un JWT.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginRequest" } } }
        },
        "responses": {
          "200": { "description": "Sesión iniciada.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginResponse" } } } },
          "400": { "description": "Faltan cédula/clave o el formato es inválido." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "description": "El acceso al portal no está autorizado (patient_portal_authorized distinto de 1). Debe autorizarlo Operaciones TuDrGroup." }
        }
      }
    },
    "/api/endpoints": {
      "get": {
        "tags": ["Documentación"],
        "summary": "Catálogo de endpoints",
        "description": "Devuelve el catálogo JSON de los endpoints publicados.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/dashboard/venezuela-by-state": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Dashboard de Venezuela por estado",
        "description": "Obtiene indicadores del dashboard desglosados por estado.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agents": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Métricas de agentes",
        "description": "Consulta indicadores agregados de agentes de corretaje.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agents/by-state": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Agentes por estado",
        "description": "Agrupa los agentes de corretaje por estado.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agents/by-active-affiliations": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Agentes por afiliaciones activas",
        "description": "Clasifica agentes por la cantidad de afiliaciones activas.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agents/by-active-affiliation-amount": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Monto activo por agente",
        "description": "Agrupa agentes según el monto de sus afiliaciones activas.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agents/sales-by-state": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Ventas de agentes por estado",
        "description": "Desglosa las ventas atribuidas a agentes por estado.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agents/registration-comparison": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Comparación de registros de agentes",
        "description": "Compara registros de agentes entre períodos.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Métricas de agencias",
        "description": "Consulta indicadores agregados de agencias de corretaje.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/registration-comparison": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Comparación de registros de agencias",
        "description": "Compara registros de agencias entre períodos.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/by-state": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Agencias por estado",
        "description": "Agrupa las agencias de corretaje por estado.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/by-active-affiliations": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Agencias por afiliaciones activas",
        "description": "Clasifica agencias por su cantidad de afiliaciones activas.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/by-active-affiliations/by-agency": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones activas por agencia",
        "description": "Detalla las afiliaciones activas de cada agencia.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/by-active-corporate-affiliations": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Agencias por afiliaciones corporativas",
        "description": "Clasifica agencias por afiliaciones corporativas activas.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/by-active-corporate-affiliations/by-agency": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones corporativas por agencia",
        "description": "Detalla afiliaciones corporativas activas para cada agencia.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/corretaje/agencies/by-active-affiliation-amount": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Monto activo por agencia",
        "description": "Agrupa agencias según el monto de sus afiliaciones activas.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/cotizaciones/status-comparison": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Cotizaciones por estatus",
        "description": "Compara la cantidad de cotizaciones por estatus.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/cotizaciones/by-agent": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Cotizaciones por agente",
        "description": "Agrupa las cotizaciones por agente.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/cotizaciones/by-agency": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Cotizaciones por agencia",
        "description": "Agrupa las cotizaciones por agencia.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/status-comparison": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones por estatus",
        "description": "Compara afiliaciones por estatus.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/by-month": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones por mes",
        "description": "Agrupa afiliaciones por mes.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/by-day": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones por día",
        "description": "Agrupa afiliaciones por día.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/by-plan-month": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones por plan y mes",
        "description": "Desglosa afiliaciones por plan y mes.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/by-plan-amount": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Monto por plan",
        "description": "Agrupa el monto de afiliaciones por plan.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/by-plan-amount-combined": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Monto combinado por plan",
        "description": "Obtiene el indicador combinado de montos por plan.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/metrics/afiliaciones/by-state": {
      "get": {
        "tags": ["Métricas"],
        "summary": "Afiliaciones por estado",
        "description": "Agrupa afiliaciones por estado.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/emails/bulk": {
      "post": {
        "tags": ["Correos"],
        "summary": "Enviar correos masivos",
        "description": "Programa el envío de una campaña de correo; `dry_run` permite validarla sin enviarla.",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["recipients", "subject"],
                "properties": {
                  "recipients": { "type": "string", "description": "Destinatarios, según el formato admitido por el servicio." },
                  "copy": { "type": "string", "description": "Destinatarios en copia opcionales." },
                  "subject": { "type": "string", "example": "Información importante" },
                  "image": { "type": "string", "format": "binary" },
                  "logo": { "type": "string", "format": "binary" },
                  "dry_run": { "type": "boolean", "default": false }
                }
              }
            }
          }
        },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/notifications/whatsapp/status": {
      "get": {
        "tags": ["Mensajería"],
        "summary": "Estado de WhatsApp",
        "description": "Consulta la configuración y disponibilidad del proveedor de WhatsApp.",
        "security": [{ "ApiKeyAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/notifications/mass/send-batch": {
      "post": {
        "tags": ["Mensajería"],
        "summary": "Enviar lote de WhatsApp",
        "description": "Envía un lote de notificaciones masivas de WhatsApp.",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/notifications/mass/send": {
      "post": {
        "tags": ["Mensajería"],
        "summary": "Enviar WhatsApp masivo",
        "description": "Crea un envío masivo de notificaciones de WhatsApp.",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/notifications/birthday/test": {
      "post": {
        "tags": ["Mensajería"],
        "summary": "Probar saludo de cumpleaños",
        "description": "Ejecuta una prueba del flujo de notificaciones de cumpleaños.",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/affiliates": { "get": { "tags": ["Recursos"], "summary": "Listar afiliados", "description": "Devuelve afiliados con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/affiliate-corporates": { "get": { "tags": ["Recursos"], "summary": "Listar afiliados corporativos", "description": "Devuelve afiliados corporativos con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/agencies": { "get": { "tags": ["Recursos"], "summary": "Listar agencias", "description": "Devuelve agencias con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/agents": { "get": { "tags": ["Recursos"], "summary": "Listar agentes", "description": "Devuelve agentes con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/rrhh-colaboradores": { "get": { "tags": ["Recursos"], "summary": "Listar colaboradores", "description": "Devuelve colaboradores de RR. HH. con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/telemedicine-doctors": { "get": { "tags": ["Recursos"], "summary": "Listar médicos de telemedicina", "description": "Devuelve médicos de telemedicina con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/suppliers": { "get": { "tags": ["Recursos"], "summary": "Listar proveedores", "description": "Devuelve proveedores con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/doctor-nurses": { "get": { "tags": ["Recursos"], "summary": "Listar médicos y enfermeros", "description": "Devuelve médicos y enfermeros con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/travel-agencies": { "get": { "tags": ["Recursos"], "summary": "Listar agencias de viaje", "description": "Devuelve agencias de viaje con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/travel-agents": { "get": { "tags": ["Recursos"], "summary": "Listar agentes de viaje", "description": "Devuelve agentes de viaje con paginación.", "security": [{ "ApiKeyAuth": [] }], "parameters": [{ "$ref": "#/components/parameters/Page" }], "responses": { "200": { "$ref": "#/components/responses/PaginatedSuccess" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/auth/me": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Sesión actual",
        "description": "Devuelve la identidad asociada al JWT.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/auth/logout": {
      "post": {
        "tags": ["Portal Paciente"],
        "summary": "Cerrar sesión",
        "description": "Finaliza la sesión del cliente; el JWT debe descartarse.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/me/profile": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Perfil del paciente",
        "description": "Obtiene el perfil privado del paciente autenticado.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      }
    },
    "/api/clinical-history": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Historia clínica",
        "description": "Obtiene la historia clínica disponible del paciente.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      },
      "post": {
        "tags": ["Portal Paciente"],
        "summary": "Registrar historia clínica (onboarding)",
        "description": "Alta inicial de historia clínica desde el wizard del portal. Responde 409 si ya existe.",
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "additionalProperties": true }
            }
          }
        },
        "responses": {
          "201": { "$ref": "#/components/responses/Success" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "409": { "description": "El paciente ya tiene historia clínica." }
        }
      }
    },
    "/api/clinical-history/pdf": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "PDF de historia clínica",
        "description": "Descarga o entrega la representación PDF de la historia clínica.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "description": "Archivo PDF o respuesta exitosa." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      }
    },
    "/api/documents": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Listar documentos",
        "description": "Lista los documentos disponibles para el paciente.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      },
      "post": {
        "tags": ["Portal Paciente"],
        "summary": "Registrar documento",
        "description": "Registra un documento para el paciente autenticado.",
        "security": [{ "BearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/documents/{source}/{id}/download": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Descargar documento",
        "description": "Descarga un documento por su fuente e identificador.",
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "source", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Archivo descargable." }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      }
    },
    "/api/cases": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Listar casos",
        "description": "Obtiene los casos asociados al paciente.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/reminders": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Listar recordatorios",
        "description": "Obtiene los recordatorios del paciente autenticado.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      },
      "post": {
        "tags": ["Portal Paciente"],
        "summary": "Crear recordatorio",
        "description": "Crea un recordatorio para el paciente autenticado.",
        "security": [{ "BearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/reminders/{id}": {
      "put": {
        "tags": ["Portal Paciente"],
        "summary": "Reemplazar recordatorio",
        "description": "Actualiza por completo un recordatorio existente.",
        "security": [{ "BearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ReminderId" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      },
      "patch": {
        "tags": ["Portal Paciente"],
        "summary": "Actualizar recordatorio",
        "description": "Actualiza parcialmente un recordatorio existente.",
        "security": [{ "BearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ReminderId" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      },
      "delete": {
        "tags": ["Portal Paciente"],
        "summary": "Eliminar recordatorio",
        "description": "Elimina un recordatorio del paciente.",
        "security": [{ "BearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ReminderId" }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      }
    },
    "/api/reminders/{id}/toggle": {
      "patch": {
        "tags": ["Portal Paciente"],
        "summary": "Alternar recordatorio",
        "description": "Cambia el estado activo o completado de un recordatorio.",
        "security": [{ "BearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ReminderId" }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } }
      }
    },
    "/api/help/contacts": {
      "get": {
        "tags": ["Portal Paciente"],
        "summary": "Contactos de ayuda",
        "description": "Obtiene los canales de ayuda disponibles para el paciente.",
        "security": [{ "BearerAuth": [] }],
        "responses": { "200": { "$ref": "#/components/responses/Success" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": { "type": "apiKey", "in": "header", "name": "X-API-Key" },
      "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" }
    },
    "parameters": {
      "Page": { "name": "page", "in": "query", "description": "Página solicitada, empezando en 1.", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
      "ReminderId": { "name": "id", "in": "path", "required": true, "description": "Identificador del recordatorio.", "schema": { "type": "string" } }
    },
    "schemas": {
      "SuccessResponse": {
        "type": "object",
        "description": "Respuesta exitosa genérica; la propiedad `data` depende del endpoint.",
        "properties": { "success": { "type": "boolean", "example": true }, "data": { "nullable": true } }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": { "success": { "type": "boolean", "example": false }, "message": { "type": "string", "example": "No autorizado." } }
      },
      "Pagination": {
        "type": "object",
        "properties": { "page": { "type": "integer", "example": 1 }, "limit": { "type": "integer", "example": 50 }, "total": { "type": "integer", "example": 120 }, "totalPages": { "type": "integer", "example": 3 } }
      },
      "LoginRequest": {
        "type": "object",
        "required": ["nro_identificacion", "password"],
        "properties": {
          "nro_identificacion": { "type": "string", "example": "V-12345678" },
          "password": { "type": "string", "example": "clave-del-portal", "description": "Clave en texto plano (patient_portal_password)." },
          "patient_portal_password": { "type": "string", "description": "Alias opcional de password." }
        }
      },
      "LoginResponse": {
        "type": "object",
        "properties": { "token": { "type": "string", "description": "JWT de acceso." }, "token_type": { "type": "string", "example": "Bearer" }, "expires_in": { "type": "string", "example": "8h" } }
      }
    },
    "responses": {
      "Success": { "description": "Operación realizada correctamente.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuccessResponse" } } } },
      "PaginatedSuccess": { "description": "Listado paginado obtenido correctamente.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessResponse" }, { "type": "object", "properties": { "pagination": { "$ref": "#/components/schemas/Pagination" } } }] } } } },
      "Unauthorized": { "description": "Credenciales ausentes, inválidas o expiradas.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "NotFound": { "description": "El recurso solicitado no existe o no está disponible.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
    }
  },
  "externalDocs": {
    "description": "Catálogo HTML de endpoints",
    "url": "/docs/endpoints.html"
  }
}
