openapi: "3.0.3"
info:
  title: API Cyber Pro — Ubiqs
  version: "1.0.0"
  description: |
    API REST para cotización y emisión de pólizas del seguro **Cyber Pro Individual** (Producto 401) del INS,
    expuesta por Ubiqs como capa de abstracción para las aplicaciones de Mutual Seguros.

    ## Características
    - Esquema de request simplificado
    - Validación y normalización automática
    - Resolución inteligente de ubicaciones (nombres → códigos)
    - Gestión automática de autenticación con el INS
    - Respuestas normalizadas con errores tipificados
    - Flujo de consentimiento informado integrado
    - Registro auditable de cada transacción

    ## Acciones soportadas
    - **COTI** — Cotización: obtiene primas y coberturas por plan y moneda
    - **EMI** — Emisión: emite la póliza con consentimiento informado
  contact:
    name: Ubiqs · Soluciones Tecnológicas
    email: cloud@boostaiagency.com

servers:
  - url: https://api-staging.boostaiagency.com
    description: Integración (pruebas) — conecta a INS sandbox real
  - url: https://api.boostaiagency.com
    description: Producción

security:
  - ApiKeyAuth: []

paths:
  /cyberpro/v1:
    post:
      summary: Cotizar o emitir póliza Cyber Pro
      description: |
        Endpoint unificado que soporta dos acciones:
        - `COTI` — Cotización del seguro
        - `EMI` — Emisión de la póliza (requiere consentimiento informado)

        La acción se determina por el campo `action` en el body.
      operationId: cyberpro
      tags:
        - Cyber Pro
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/CotiRequest"
                - $ref: "#/components/schemas/EmiRequest"
              discriminator:
                propertyName: action
                mapping:
                  COTI: "#/components/schemas/CotiRequest"
                  EMI: "#/components/schemas/EmiRequest"
            examples:
              cotizacion_crc:
                summary: Cotización en colones (Plan 3)
                value:
                  action: "COTI"
                  currency: "CRC"
                  plan: 3
                  client:
                    idType: "0"
                    idNumber: "801170740"
                    firstSurname: "FUENTES"
                    secondSurname: "MUÑIZ"
                    firstName: "DAYSI"
                    secondName: "MARGARITA"
                    birthDate: "12/04/1982"
                    gender: "F"
                  location:
                    provinceName: "San José"
                    cantonName: "Tibás"
                    districtName: "San Juan"
                  addressLine: "San Juan de Tibás, 200m norte del parque"
                  contact:
                    email: "dfuentes@ejemplo.com"
                    phone: "88887777"
                  requestId: "app-gm-coti-20260327-001"
              emision_crc:
                summary: Emisión en colones (Plan 3, Anual)
                value:
                  action: "EMI"
                  currency: "CRC"
                  plan: 3
                  paymentFrequency: "A"
                  client:
                    idType: "0"
                    idNumber: "801170740"
                    firstSurname: "FUENTES"
                    secondSurname: "MUÑIZ"
                    firstName: "DAYSI"
                    secondName: "MARGARITA"
                    birthDate: "12/04/1982"
                    gender: "F"
                  location:
                    provinceCode: "1"
                    cantonCode: "13"
                    districtCode: "01"
                  addressLine: "San Juan de Tibás, 200m norte del parque"
                  contact:
                    email: "dfuentes@ejemplo.com"
                    phone: "88887777"
                  consent:
                    accepted: true
                    version: "cyberpro-consent-v1"
                    timestamp: "2026-03-27T14:30:00-06:00"
                  requestId: "app-gm-emi-20260327-001"
      responses:
        "200":
          description: Operación exitosa
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/CotiResponse"
                  - $ref: "#/components/schemas/EmiResponse"
              examples:
                cotizacion_exitosa:
                  summary: Cotización exitosa CRC Plan 3
                  value:
                    ok: true
                    action: "COTI"
                    currency: "CRC"
                    plan: 3
                    numeroCotizacion: "CT-TMP-2026-04194329"
                    primas:
                      - frecuencia: "Anual"
                        codigo: "A"
                        montoPrima: 37647.0
                      - frecuencia: "Semestral"
                        codigo: "S"
                        montoPrima: 18824.0
                      - frecuencia: "Trimestral"
                        codigo: "T"
                        montoPrima: 9412.0
                      - frecuencia: "Mensual"
                        codigo: "M"
                        montoPrima: 3136.0
                    coberturas:
                      - codigo: "40A"
                        descripcion: "FRAUDE EN LINEA"
                        sumaAsegurada: 1350000
                        prima: 33316
                        impuesto: 0
                        total: 33316
                      - codigo: "40B"
                        descripcion: "RIESGO DEL SISTEMA DOMESTICO"
                        sumaAsegurada: 1350000
                        prima: 0
                        impuesto: 0
                        total: 0
                      - codigo: "40C"
                        descripcion: "ROBO DE IDENTIDAD"
                        sumaAsegurada: 1350000
                        prima: 0
                        impuesto: 0
                        total: 0
                      - codigo: "998"
                        descripcion: "IVA"
                        sumaAsegurada: 0
                        prima: 0
                        impuesto: 4331
                        total: 4331
                emision_exitosa:
                  summary: Emisión exitosa
                  value:
                    ok: true
                    action: "EMI"
                    currency: "CRC"
                    plan: 3
                    poliza:
                      numeroPoliza: "0101SRC000021700"
                      descripcionLinea: "040 - SEGURO RIESGO CIBERNÉTICO"
                      descripcionProducto: "401 - Seguro Cyber Pro Individual"
                      fechaVigenciaDesde: "27/03/2026"
                      fechaVigenciaHasta: "27/03/2027"
                      frecuenciaPagoTexto: "Costo Anual (IVA) :"
                      montoPrima: 37647.0
                      montoPrimaNeta: 33316.0
        "400":
          description: Error de validación, consentimiento o ubicación ambigua
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                validation_error:
                  summary: Campos faltantes
                  value:
                    ok: false
                    error:
                      type: "VALIDATION_ERROR"
                      message: "Campos obligatorios faltantes o inválidos"
                      details:
                        missing: ["client.idNumber", "contact.email"]
                        invalid: ["client.birthDate"]
                consent_required:
                  summary: Emisión sin consentimiento
                  value:
                    ok: false
                    error:
                      type: "CONSENT_REQUIRED"
                      message: "La emisión requiere consentimiento informado del cliente"
                      details:
                        requiredFields: ["consent.accepted", "consent.version", "consent.timestamp"]
                        consentVersion: "cyberpro-consent-v1"
                location_ambiguous:
                  summary: Ubicación con múltiples coincidencias
                  value:
                    ok: false
                    error:
                      type: "LOCATION_AMBIGUOUS"
                      message: "Se encontraron múltiples coincidencias para la ubicaci��n"
                      details:
                        field: "districtName"
                        value: "San Juan"
                        candidates:
                          - province: "San José"
                            canton: "Tibás"
                            district: "San Juan"
                            codes:
                              province: "1"
                              canton: "13"
                              district: "01"
                          - province: "Alajuela"
                            canton: "Poás"
                            district: "San Juan"
                            codes:
                              province: "2"
                              canton: "06"
                              district: "02"
        "401":
          description: API key inválida o no proporcionada
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                unauthorized:
                  value:
                    ok: false
                    error:
                      type: "UNAUTHORIZED"
                      message: "API key inválida o no proporcionada"
        "502":
          description: Error del INS
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                ins_error:
                  value:
                    ok: false
                    error:
                      type: "INS_ERROR"
                      message: "El INS rechazó la solicitud"
                      details:
                        status: 400
                        codigoEstado: "99"
                        detail: "El número de identificación no corresponde al tipo indicado"
        "503":
          description: Error de conectividad con el INS
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                network_error:
                  value:
                    ok: false
                    error:
                      type: "NETWORK_ERROR"
                      message: "Error de conectividad con el servicio del INS"
        "504":
          description: Timeout del INS
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                upstream_timeout:
                  value:
                    ok: false
                    error:
                      type: "UPSTREAM_TIMEOUT"
                      message: "El servicio del INS no respondió en el tiempo esperado"

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: |
        Clave API proporcionada por Ubiqs al inicio de la integración.
        Una clave por canal (app móvil, web, WhatsApp, etc.).
        Rotación bajo solicitud, sin downtime.

  schemas:
    # --- Request Schemas ---

    ClientObject:
      type: object
      required: [idType, idNumber, firstSurname, secondSurname, firstName, birthDate, gender]
      properties:
        idType:
          type: string
          enum: ["0", "6", "9", "12"]
          description: |
            Tipo de identificación:
            - `"0"` — Cédula Física Nacional
            - `"6"` — DIMEX (Documento Único)
            - `"9"` — Pasaporte
            - `"12"` — Cédula de Cuerpos Diplomáticos
        idNumber:
          type: string
          maxLength: 17
          description: Número de identificación
        firstSurname:
          type: string
          maxLength: 30
          description: Primer apellido
        secondSurname:
          type: string
          maxLength: 30
          description: Segundo apellido
        firstName:
          type: string
          maxLength: 20
          description: Primer nombre
        secondName:
          type: string
          maxLength: 20
          description: Segundo nombre (opcional)
        birthDate:
          type: string
          pattern: "^\\d{2}/\\d{2}/\\d{4}$"
          description: Fecha de nacimiento (DD/MM/AAAA)
          example: "12/04/1982"
        gender:
          type: string
          enum: ["M", "F"]
          description: Género

    LocationObject:
      type: object
      description: |
        Ubicación del asegurado. Se puede enviar por **códigos** o por **nombres** (la API resuelve automáticamente).
        Enviar un juego completo (códigos O nombres).
      properties:
        provinceCode:
          type: string
          enum: ["1", "2", "3", "4", "5", "6", "7"]
          description: "Código de provincia (1=San José, 2=Alajuela, 3=Cartago, 4=Heredia, 5=Guanacaste, 6=Puntarenas, 7=Limón)"
        cantonCode:
          type: string
          description: Código de cantón (01-20)
        districtCode:
          type: string
          description: Código de distrito (01-16)
        provinceName:
          type: string
          description: Nombre de provincia
          example: "San José"
        cantonName:
          type: string
          description: Nombre de cantón
          example: "Tibás"
        districtName:
          type: string
          description: Nombre de distrito
          example: "San Juan"

    ContactObject:
      type: object
      required: [email, phone]
      properties:
        email:
          type: string
          format: email
          description: Correo electrónico
        phone:
          type: string
          description: Teléfono
          example: "88887777"

    ConsentObject:
      type: object
      required: [accepted, version, timestamp]
      description: Consentimiento informado del cliente (obligatorio para EMI)
      properties:
        accepted:
          type: boolean
          description: El cliente aceptó el consentimiento (debe ser true)
        version:
          type: string
          description: Versión del texto de consentimiento
          example: "cyberpro-consent-v1"
        timestamp:
          type: string
          format: date-time
          description: Fecha/hora de aceptación (ISO 8601)
          example: "2026-03-27T14:30:00-06:00"

    CotiRequest:
      type: object
      required: [action, currency, plan, client, location, addressLine, contact]
      properties:
        action:
          type: string
          enum: ["COTI"]
        currency:
          type: string
          enum: ["CRC", "USD"]
          description: Moneda de la cotización
        plan:
          type: integer
          enum: [1, 2, 3, 4]
          description: |
            Plan seleccionado:
            - Plan 1: CRC ₡540,000 / USD $1,000
            - Plan 2: CRC ₡1,080,000 / USD $2,000
            - Plan 3: CRC ₡1,350,000 / USD $2,500
            - Plan 4: CRC ₡2,700,000 / USD $5,000
        client:
          $ref: "#/components/schemas/ClientObject"
        location:
          $ref: "#/components/schemas/LocationObject"
        addressLine:
          type: string
          maxLength: 354
          description: Dirección completa
        contact:
          $ref: "#/components/schemas/ContactObject"
        requestId:
          type: string
          maxLength: 64
          description: ID de correlación del cliente (opcional)

    EmiRequest:
      type: object
      required: [action, currency, plan, paymentFrequency, client, location, addressLine, contact, consent]
      properties:
        action:
          type: string
          enum: ["EMI"]
        currency:
          type: string
          enum: ["CRC", "USD"]
        plan:
          type: integer
          enum: [1, 2, 3, 4]
        paymentFrequency:
          type: string
          enum: ["A", "S", "T", "M"]
          description: |
            Frecuencia de pago:
            - `A` — Anual
            - `S` — Semestral
            - `T` — Trimestral
            - `M` — Mensual
        client:
          $ref: "#/components/schemas/ClientObject"
        location:
          $ref: "#/components/schemas/LocationObject"
        addressLine:
          type: string
          maxLength: 354
        contact:
          $ref: "#/components/schemas/ContactObject"
        consent:
          $ref: "#/components/schemas/ConsentObject"
        requestId:
          type: string
          maxLength: 64

    # --- Response Schemas ---

    PrimaItem:
      type: object
      properties:
        frecuencia:
          type: string
          description: Nombre de la frecuencia
          example: "Anual"
        codigo:
          type: string
          enum: ["A", "S", "T", "M"]
          description: Código de frecuencia
        montoPrima:
          type: number
          description: Monto total de la prima (IVA incluido)

    CoberturaItem:
      type: object
      properties:
        codigo:
          type: string
          description: Código de cobertura (40A, 40B, 40C, 998)
        descripcion:
          type: string
          description: Descripción de la cobertura
        sumaAsegurada:
          type: number
        prima:
          type: number
          description: Prima neta
        impuesto:
          type: number
          description: IVA aplicado
        total:
          type: number
          description: Total (prima + impuesto)

    PolizaObject:
      type: object
      properties:
        numeroPoliza:
          type: string
          description: Número de póliza emitida por el INS
        descripcionLinea:
          type: string
        descripcionProducto:
          type: string
        fechaVigenciaDesde:
          type: string
          description: Inicio de vigencia (DD/MM/AAAA)
        fechaVigenciaHasta:
          type: string
          description: Fin de vigencia (DD/MM/AAAA)
        frecuenciaPagoTexto:
          type: string
        montoPrima:
          type: number
          description: Prima total (con IVA)
        montoPrimaNeta:
          type: number
          description: Prima neta (sin IVA)

    CotiResponse:
      type: object
      properties:
        ok:
          type: boolean
          example: true
        action:
          type: string
          example: "COTI"
        currency:
          type: string
          enum: ["CRC", "USD"]
        plan:
          type: integer
        numeroCotizacion:
          type: string
          description: Número de cotización asignado por el INS
        primas:
          type: array
          items:
            $ref: "#/components/schemas/PrimaItem"
          description: Array con las 4 frecuencias de pago
        coberturas:
          type: array
          items:
            $ref: "#/components/schemas/CoberturaItem"
          description: Array de coberturas incluidas

    EmiResponse:
      type: object
      properties:
        ok:
          type: boolean
          example: true
        action:
          type: string
          example: "EMI"
        currency:
          type: string
          enum: ["CRC", "USD"]
        plan:
          type: integer
        poliza:
          $ref: "#/components/schemas/PolizaObject"

    # --- Error Schema ---

    ErrorResponse:
      type: object
      properties:
        ok:
          type: boolean
          example: false
        error:
          type: object
          properties:
            type:
              type: string
              enum:
                - VALIDATION_ERROR
                - CONSENT_REQUIRED
                - LOCATION_AMBIGUOUS
                - INS_ERROR
                - UNAUTHORIZED
                - NETWORK_ERROR
                - UPSTREAM_TIMEOUT
              description: Tipo de error tipificado
            message:
              type: string
              description: Descripción legible del error
            details:
              type: object
              description: Detalles adicionales según el tipo de error
              additionalProperties: true

tags:
  - name: Cyber Pro
    description: Cotización y emisión de pólizas Cyber Pro Individual (Producto 401)
