openapi: 3.0.3
info:
  title: Panadata API v4
  description: |
    API REST para consultar y enriquecer entidades de Panamá. Esta documentación
    está organizada para que pueda pasar de una prueba manual a una integración
    real sin cambiar de contexto.

    ## Cómo probar la API

    1. Use `GET /v4/panama/entidades` para buscar por nombre o RUC.
    2. Identifique el `id` correcto en los resultados.
    3. Use `GET /v4/panama/entidades/{id}` con `include=` para enriquecer la entidad.

    ## Sandbox vs llave API propia

    El sandbox del producto usa una llave compartida del servidor y una experiencia
    guiada para pruebas manuales. Esta referencia describe la API real: úsela con
    su propia llave para automatizar llamadas desde Postman, scripts o su aplicación.

    ## Facturación

    Cada solicitud autenticada genera un cargo base de **$0.01**. Cuando se
    utiliza el parámetro de consulta `include` en el endpoint de detalle, se agrega
    el precio de los códigos de producto solicitados. En la plataforma, ese consumo
    se descuenta de un saldo prepago. La facturación ocurre **después** de que la
    solicitud sea exitosa (solo respuestas 2xx).

    Los códigos de producto utilizan resolución inteligente: los códigos se ordenan por
    cantidad de niveles de forma descendente y solo se cobran los códigos no redundantes.
    Por ejemplo, al solicitar `?include=DAT-CORE,CHK-BIN` solo se cobra DAT-CORE
    porque ya cubre el nivel `core_registro` proporcionado por CHK-BIN.
  version: 4.0.0

servers:
  - url: https://api.panadata.net
    description: Producción

security:
  - BearerAuth: []

tags:
  - name: Primeros pasos
    description: |
      Recorrido recomendado para probar la API por primera vez.

      - Empiece por **Buscar entidades** cuando todavía no conoce el `id` de la entidad.
      - Use **Enriquecer una entidad por ID** cuando ya tiene el identificador correcto.
      - El sandbox fuerza una ruta simple para pruebas guiadas, pero aquí verá la API real.
  - name: Operación del servicio
    description: |
      Endpoints auxiliares para verificar disponibilidad y estado del servicio.

x-tagGroups:
  - name: Empezar
    tags:
      - Primeros pasos
  - name: Operación
    tags:
      - Operación del servicio

x-product-codes:
  CHK-BIN:
    cost: 0.02
    description: Verificación binaria de existencia. Retorna los identificadores básicos (id y panadata_id), además de nombre y ruc/cedula.
    tags: [core_registro]
  DAT-CORE:
    cost: 0.15
    tags: [core_registro, contacto, entity_events]
  DAT-HOOK:
    cost: 0.03
    description: Feed cronológico de eventos recientes sobre el registro de la entidad. Se devuelve como `entity_events` en la respuesta del endpoint de detalle (máximo 100). Es un código pull (los datos vienen inline en la respuesta del GET) — independiente del sistema de webhooks de la plataforma.
    tags: [entity_events]
  DAT-GOV:
    cost: 0.15
    tags: [directores, suspension, organizaciones, representante_legal_identificado, gacetas, documentos_contraloria, is_itbm, last_itbm_date, funcionario]
  DAT-BIZ:
    cost: 0.08
    tags: [avisos, licencias, personal_licenses, company_licenses, fideicomisos, marcas]
  DAT-ASSET:
    cost: 0.25
    tags: [propiedades, fincas, bienes_muebles, naves]
  DAT-TRADE:
    cost: 0.20
    tags: [importaciones, exportaciones, imports_summary, exports_summary, customs_summary]
  DAT-DOC:
    cost: 0.06
    tags: [documentos_escaneados, documentos_digitales, rp_report_url]
  DAT-RISK:
    cost: 0.20
    tags: [css_moroso_menciones, sanciones, idoneidades, expedientes_judiciales]
  DAT-PROC:
    cost: 0.05
    tags: [licitaciones]
  DAT-NEWS:
    cost: 0.12
    tags: [noticias, noticias_globales]
  DAT-MEDIA:
    cost: 0.12
    tags: [noticias, noticias_globales, entity_events]
  DAT-LEGAL:
    cost: 0.10
    tags: [migrations, work_permits]
  DAT-CGR:
    cost: 0.08
    tags: [documentos_contraloria, funcionario]
  DAT-IP:
    cost: 0.03
    tags: [marcas]
  DAT-LABOR:
    cost: 0.15
    tags: [migrations, work_permits, funcionario]
  DAT-SCREEN:
    cost: 0.40
    tags: [sanciones_internacionales, coincidencias_pep]
  DAT-ALL:
    cost: 1.81
    tags:
      - core_registro
      - contacto
      - entity_events
      - directores
      - suspension
      - organizaciones
      - representante_legal_identificado
      - avisos
      - licencias
      - personal_licenses
      - company_licenses
      - propiedades
      - fincas
      - bienes_muebles
      - naves
      - importaciones
      - exportaciones
      - imports_summary
      - exports_summary
      - customs_summary
      - documentos_escaneados
      - documentos_digitales
      - rp_report_url
      - css_moroso_menciones
      - sanciones
      - sanciones_internacionales
      - coincidencias_pep
      - idoneidades
      - expedientes_judiciales
      - licitaciones
      - noticias
      - noticias_globales
      - fideicomisos
      - marcas
      - migrations
      - work_permits
      - gacetas
      - documentos_contraloria
      - is_itbm
      - last_itbm_date
      - funcionario
  DAT-ALL+:
    cost: TBD
    tags: [todos los tags con profundidad histórica completa]

paths:
  /health:
    get:
      operationId: healthCheck
      tags:
        - Operación del servicio
      summary: Estado del servicio
      description: Retorna el estado de salud del servicio. No requiere autenticación.
      security: []
      responses:
        "200":
          description: El servicio está operativo.
          content:
            application/json:
              schema:
                type: object
                required: [status, service]
                properties:
                  status:
                    type: string
                    example: ok
                  service:
                    type: string
                    example: panadata-api

  /v4/panama/entidades/{id}:
    get:
      operationId: getEntity
      tags:
        - Primeros pasos
      summary: "Paso 2: Enriquecer una entidad por ID"
      description: |
        Use este endpoint cuando ya tenga el `id` correcto de la entidad
        (obtenido en la búsqueda) y quiera enriquecerla con módulos específicos.
        La respuesta de detalle también incluye `panadata_id`.

        El parámetro de consulta `include` es **obligatorio**. El código mínimo
        es `CHK-BIN`, que retorna una verificación binaria de existencia con los
        identificadores básicos de la entidad.

        ### Códigos de producto

        | Código | Costo | Tags |
        |--------|-------|------|
        | CHK-BIN | 0.02 | Verificación binaria de existencia. Retorna: id, nombre, ruc/cedula, panadata_id |
        | DAT-CORE | 0.15 | core_registro, contacto, entity_events |
        | DAT-HOOK | 0.03 | entity_events (feed cronológico de eventos sobre el registro, máximo 100; pull, sin relación con el sistema de webhooks) |
        | DAT-GOV | 0.15 | directores, suspension, organizaciones, representante_legal_identificado, gacetas, documentos_contraloria, is_itbm, last_itbm_date, funcionario |
        | DAT-BIZ | 0.08 | avisos, licencias, personal_licenses, company_licenses, fideicomisos, marcas |
        | DAT-ASSET | 0.25 | propiedades, fincas, bienes_muebles, naves |
        | DAT-TRADE | 0.20 | importaciones, exportaciones, imports_summary, exports_summary, customs_summary |
        | DAT-DOC | 0.06 | documentos_escaneados, documentos_digitales, rp_report_url |
        | DAT-RISK | 0.20 | css_moroso_menciones, sanciones, idoneidades, expedientes_judiciales |
        | DAT-PROC | 0.05 | licitaciones |
        | DAT-NEWS | 0.12 | noticias, noticias_globales |
        | DAT-MEDIA | 0.12 | noticias, noticias_globales, entity_events |
        | DAT-LEGAL | 0.10 | migrations, work_permits |
        | DAT-CGR | 0.08 | documentos_contraloria, funcionario |
        | DAT-IP | 0.03 | marcas |
        | DAT-LABOR | 0.15 | migrations, work_permits, funcionario |
        | DAT-SCREEN | 0.40 | sanciones_internacionales, coincidencias_pep |
        | DAT-ALL | 1.81 | todos los tags |
        | DAT-ALL+ | TBD | todos los tags con profundidad histórica completa |

        Costo total = base ($0.01) + suma de precios de códigos de producto cobrados.
      parameters:
        - name: id
          in: path
          required: true
          description: ID de entidad (entero).
          schema:
            type: integer
        - name: include
          in: query
          required: true
          description: |
            Códigos de producto separados por comas para incluir secciones de datos. Obligatorio.
            El mínimo es `CHK-BIN` para una verificación binaria de existencia.
            Ejemplo: `DAT-CORE,DAT-GOV`
          schema:
            type: string
          example: DAT-CORE,DAT-GOV
      responses:
        "200":
          description: Detalle de entidad. La estructura depende del tipo de entidad (organización o persona natural).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/OrganizationDetail"
                  - $ref: "#/components/schemas/NaturalPersonDetail"
        "400":
          description: ID inválido, parámetro `include` faltante o código de producto desconocido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                invalidId:
                  summary: ID de entidad inválido
                  value:
                    error: "id must be an integer"
                unknownCode:
                  summary: Código de producto desconocido
                  value:
                    error: "unknown product code(s): INVALID-CODE"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
              example:
                message: "Unauthorized"
        "403":
          description: API key rechazada por la capa de autenticación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayForbiddenError"
              example:
                Message: "User is not authorized to access this resource with an explicit deny in an identity-based policy"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "insufficient credits"
        "404":
          description: Entidad no encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "entity not found"

  /v4/panama/entidades:
    get:
      operationId: searchEntities
      tags:
        - Primeros pasos
      summary: "Paso 1: Buscar entidades por nombre o RUC"
      description: |
        Use este endpoint para descubrir la entidad correcta antes de enriquecerla.
        Puede buscar organizaciones y personas naturales por nombre y/o RUC.
        Se requiere al menos uno de `nombre` o `ruc`. Retorna hasta 20 resultados.

        Costo: $0.01 por solicitud.
      parameters:
        - name: nombre
          in: query
          required: false
          description: Nombre de entidad a buscar.
          schema:
            type: string
          example: Panadata
        - name: ruc
          in: query
          required: false
          description: Número de RUC a buscar.
          schema:
            type: string
          example: "155640453"
      responses:
        "200":
          description: Resultados de búsqueda.
          content:
            application/json:
              schema:
                type: array
                maxItems: 20
                items:
                  $ref: "#/components/schemas/EntitySummary"
        "400":
          description: Parámetros de consulta requeridos faltantes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "at least one of 'nombre' or 'ruc' is required"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
              example:
                message: "Unauthorized"
        "403":
          description: API key rechazada por la capa de autenticación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayForbiddenError"
              example:
                Message: "User is not authorized to access this resource with an explicit deny in an identity-based policy"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "insufficient credits"

  /v4/panama/entidades/{id}/update:
    post:
      operationId: createUpdateRequest
      summary: Solicitar actualización de entidad panameña
      description: |
        Encola una solicitud de actualización de datos para la entidad con el `id`
        dado. El scraper corre en background y, una vez completado, llama al
        webhook configurado en la cuenta del usuario con el resultado.

        Si no tiene webhook configurado, podés pollear el estado con
        `GET /v4/update_requests/{update_request_id}`.

        Costo: suma de costos de los códigos de producto solicitados. Se
        descuenta al confirmar el resultado (no al crear la solicitud). El
        costo base ($0.01) **no** se cobra en este endpoint.
      parameters:
        - name: id
          in: path
          required: true
          description: ID de entidad panameña (entero).
          schema:
            type: integer
        - name: include
          in: query
          required: true
          description: Códigos de producto separados por comas. Al menos uno es requerido.
          schema:
            type: string
          example: DAT-CORE,DAT-GOV
      responses:
        "202":
          description: Solicitud de actualización creada exitosamente.
          content:
            application/json:
              schema:
                type: object
                required: [update_request_id, status, entity_id, entity_sid, jurisdiction, requested_codes, estimated_cost, webhook_url]
                properties:
                  update_request_id:
                    type: integer
                  status:
                    type: string
                    enum: [pending]
                  entity_id:
                    type: integer
                  entity_sid:
                    type: string
                  jurisdiction:
                    type: string
                    enum: [panama]
                  requested_codes:
                    type: array
                    items:
                      type: string
                  estimated_cost:
                    type: string
                  webhook_url:
                    type: string
                    nullable: true
        "400":
          description: ID inválido, código de producto desconocido, o parámetro faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "insufficient credits"
        "403":
          description: API key rechazada o el plan gratuito no puede crear solicitudes de actualización.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/GatewayForbiddenError"
                  - $ref: "#/components/schemas/Error"
              examples:
                paidPlanOnly:
                  summary: Plan gratuito no soportado
                  value:
                    error: "update requests require a paid plan"
        "404":
          description: Entidad no encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "entity not found"

  /v4/update_requests/{update_request_id}:
    get:
      operationId: getUpdateRequest
      summary: Estado de una solicitud de actualización
      description: |
        Retorna el estado y resultado de una solicitud creada con
        `POST /v4/panama/entidades/{id}/update`. El `update_request_id` es
        globalmente único; un mismo endpoint cubre Panamá, Colombia y Ecuador.

        La respuesta siempre tiene las mismas 11 claves top-level
        independiente del estado (`pending`, `completed`, `failed`); las
        ausentes se devuelven como `null`.

        `status` y `webhook_status` son independientes: un scrape exitoso
        cuyo webhook falló se devuelve con `status=completed` y `result`
        poblado, mientras `webhook_status=failed` describe el fallo de
        entrega en `error.message`.
      parameters:
        - name: update_request_id
          in: path
          required: true
          description: ID entero de la solicitud.
          schema:
            type: integer
      responses:
        "200":
          description: Estado de la solicitud.
          headers:
            Cache-Control:
              schema:
                type: string
              description: Siempre `no-store`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateRequestStatus"
        "400":
          description: "`update_request_id` no es un entero válido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
        "403":
          description: API key rechazada o el plan gratuito no puede acceder a solicitudes de actualización.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/GatewayForbiddenError"
                  - $ref: "#/components/schemas/Error"
        "404":
          description: Solicitud no encontrada o no pertenece al caller.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: "update request not found"

  /v4/ecuador/entidades/{id}:
    get:
      operationId: getEntityEcuador
      summary: Obtener detalle de organización ecuatoriana
      description: |
        Retorna el detalle de una organización ecuatoriana. El parámetro
        `include` es **obligatorio**. El catálogo Ecuador hoy se limita a
        `CHK-BIN` (0.02), `DAT-CORE` (0.15) y `DAT-ALL` (0.85). Los SKUs
        intermedios están temporalmente deshabilitados pendiente pricing.

        Las keys del SKU que no aplican no aparecen en la respuesta.
      parameters:
        - name: id
          in: path
          required: true
          description: ID de entidad (entero).
          schema:
            type: integer
        - name: include
          in: query
          required: true
          description: Códigos de producto separados por comas. Mínimo `CHK-BIN`.
          schema:
            type: string
          example: DAT-CORE
      responses:
        "200":
          description: Detalle de entidad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationDetailEcuador"
        "400":
          description: ID inválido o código de producto desconocido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: API key rechazada por la capa de autenticación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayForbiddenError"
        "404":
          description: Entidad no encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v4/ecuador/entidades:
    get:
      operationId: searchEntitiesEcuador
      summary: Buscar organizaciones ecuatorianas
      description: |
        Busca organizaciones ecuatorianas por nombre y/o RUC. Se requiere al
        menos uno de `nombre` o `ruc`. Retorna hasta 20 resultados. Costo:
        $0.01 por solicitud.
      parameters:
        - name: nombre
          in: query
          required: false
          schema:
            type: string
        - name: ruc
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Resultados de búsqueda.
          content:
            application/json:
              schema:
                type: array
                maxItems: 20
                items:
                  $ref: "#/components/schemas/EntitySummary"
        "400":
          description: Parámetros de consulta requeridos faltantes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: API key rechazada por la capa de autenticación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayForbiddenError"

  /v4/colombia/entidades/{id}:
    get:
      operationId: getEntityColombia
      summary: Obtener detalle de entidad colombiana
      description: |
        Retorna el detalle de una organización o persona natural colombiana.
        El parámetro `include` es **obligatorio**. El catálogo Colombia hoy
        se limita a `CHK-BIN` (0.02) y `DAT-CORE` (0.10).
      parameters:
        - name: id
          in: path
          required: true
          description: ID de entidad (entero).
          schema:
            type: integer
        - name: include
          in: query
          required: true
          description: Códigos de producto separados por comas. Mínimo `CHK-BIN`.
          schema:
            type: string
          example: DAT-CORE
      responses:
        "200":
          description: Detalle de entidad.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/OrganizationDetailColombia"
                  - $ref: "#/components/schemas/NaturalPersonDetailColombia"
        "400":
          description: ID inválido o código de producto desconocido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: API key rechazada por la capa de autenticación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayForbiddenError"
        "404":
          description: Entidad no encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v4/colombia/entidades:
    get:
      operationId: searchEntitiesColombia
      summary: Buscar entidades colombianas
      description: |
        Busca organizaciones y personas naturales colombianas por nombre y/o
        NIT (parámetro llamado `ruc` por consistencia entre jurisdicciones).
        Se requiere al menos uno de `nombre` o `ruc`. Costo: $0.01 por
        solicitud.
      parameters:
        - name: nombre
          in: query
          required: false
          schema:
            type: string
        - name: ruc
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Resultados de búsqueda.
          content:
            application/json:
              schema:
                type: array
                maxItems: 20
                items:
                  $ref: "#/components/schemas/EntitySummary"
        "400":
          description: Parámetros de consulta requeridos faltantes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Header Authorization faltante.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayUnauthorizedError"
        "402":
          description: Saldo prepago insuficiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: API key rechazada por la capa de autenticación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayForbiddenError"

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: |
        API key con prefijo `pk_`. Se envía como `Authorization: Bearer pk_...`.

  schemas:
    # ------------------------------------------------------------------
    # Esquemas de detalle de entidad
    # ------------------------------------------------------------------
    OrganizationDetail:
      title: "Detalle de Organización"
      type: object
      description: |
        Detalle de una entidad de tipo organización. Los campos base siempre se
        retornan y corresponden al tag `core_registro`, cubierto por `CHK-BIN`
        y también por `DAT-CORE`. Las propiedades de tags solo están presentes cuando el código
        de producto correspondiente se solicita mediante el parámetro `include`.
      required: [id, panadata_id, sid, nombre]
      properties:
        id:
          type: integer
        panadata_id:
          type: integer
          description: Identificador público estable de la entidad (actualmente igual a id).
        sid:
          type: string
        nombre:
          type: string
          nullable: true
        ficha:
          type: string
          nullable: true
        folio:
          type: string
          nullable: true
        ruc:
          type: string
          nullable: true
        ruc_no_dv:
          type: string
          nullable: true
        tipo_organizacion:
          type: string
          nullable: true
        fecha_registro:
          type: string
          nullable: true
        capital:
          type: string
          nullable: true
        domicilio:
          type: string
          nullable: true
        status:
          type: string
          nullable: true
        vigencia:
          type: string
          nullable: true
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.
        # --- propiedades de tags (incluidas mediante códigos de producto) ---
        contacto:
          description: "Tag: contacto (DAT-CORE). Información de contacto de datos derivados."
          type: object
          nullable: true
        entity_events:
          description: "Tag: entity_events (DAT-CORE, DAT-HOOK). Eventos recientes de la entidad, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EntityEvent"
        directores:
          description: "Tag: directores (DAT-GOV). Junta directiva de los datos de la entidad."
          type: array
          nullable: true
          items:
            type: object
        suspension:
          description: "Tag: suspension (DAT-GOV). Estado de suspensión de datos derivados."
          type: object
          nullable: true
        organizaciones:
          description: "Tag: organizaciones (DAT-GOV). Membresías en organizaciones, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/OrganizationMembership"
        representante_legal_identificado:
          description: "Tag: representante_legal_identificado (DAT-GOV). Representante legal de datos derivados."
          type: object
          nullable: true
        gacetas:
          description: "Tag: gacetas (DAT-GOV). Menciones en Gaceta Oficial, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Gaceta"
        documentos_contraloria:
          description: "Tag: documentos_contraloria (DAT-GOV). Documentos de la Contraloría, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/ContraloriaDoc"
        is_itbm:
          description: "Tag: is_itbm (DAT-GOV). Indica si la entidad es contribuyente de ITBM."
          type: boolean
          nullable: true
        last_itbm_date:
          description: "Tag: last_itbm_date (DAT-GOV). Fecha de última declaración de ITBM."
          type: string
          nullable: true
        funcionario:
          description: "Tag: funcionario (DAT-GOV). Registros de planilla de funcionarios públicos, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Planilla"
        avisos:
          description: "Tag: avisos (DAT-BIZ). Avisos de operación, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/BusinessNotice"
        licencias:
          description: "Tag: licencias (DAT-BIZ). Licencias generales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/GeneralLicense"
        personal_licenses:
          description: "Tag: personal_licenses (DAT-BIZ). Licencias personales/profesionales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/PersonalLicense"
        company_licenses:
          description: "Tag: company_licenses (DAT-BIZ). Licencias de empresa, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/CompanyLicense"
        fideicomisos:
          description: "Tag: fideicomisos (DAT-BIZ). Fideicomisos, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Fideicomiso"
        marcas:
          description: "Tag: marcas (DAT-BIZ). Marcas registradas, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Marca"
        propiedades:
          description: "Tag: propiedades (DAT-ASSET). Propiedades horizontales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Propiedad"
        fincas:
          description: "Tag: fincas (DAT-ASSET). Fincas, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Finca"
        bienes_muebles:
          description: "Tag: bienes_muebles (DAT-ASSET). Bienes muebles, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/BienMueble"
        naves:
          description: "Tag: naves (DAT-ASSET). Naves, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Nave"
        importaciones:
          description: "Tag: importaciones (DAT-TRADE). Registros de importación, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Importacion"
        exportaciones:
          description: "Tag: exportaciones (DAT-TRADE). Registros de exportación, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Exportacion"
        imports_summary:
          description: "Tag: imports_summary (DAT-TRADE). Estadísticas agregadas de importación de datos derivados."
          type: object
          nullable: true
        exports_summary:
          description: "Tag: exports_summary (DAT-TRADE). Estadísticas agregadas de exportación de datos derivados."
          type: object
          nullable: true
        customs_summary:
          description: "Tag: customs_summary (DAT-TRADE). Resúmenes combinados de importación y exportación."
          type: object
          nullable: true
          properties:
            imports:
              type: object
              nullable: true
            exports:
              type: object
              nullable: true
        documentos_escaneados:
          description: "Tag: documentos_escaneados (DAT-DOC). Documentos escaneados, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/DocumentoEscaneado"
        documentos_digitales:
          description: "Tag: documentos_digitales (DAT-DOC). Documentos digitales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/DocumentoDigital"
        rp_report_url:
          description: "Tag: rp_report_url (DAT-DOC). URL pre-firmada de S3 para informe del Registro Público."
          type: string
          nullable: true
        css_moroso_menciones:
          description: "Tag: css_moroso_menciones (DAT-RISK). Menciones como moroso de la CSS, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/CSSMorosoMencion"
        sanciones:
          description: "Tag: sanciones (DAT-RISK). Sanciones, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Sancion"
        idoneidades:
          description: "Tag: idoneidades (DAT-RISK). Idoneidades profesionales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Idoneidad"
        expedientes_judiciales:
          description: "Tag: expedientes_judiciales (DAT-RISK). Expedientes judiciales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/ExpedienteJudicial"
        licitaciones:
          description: "Tag: licitaciones (DAT-PROC). Licitaciones públicas, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Licitacion"
        noticias:
          description: "Tag: noticias (DAT-NEWS). Menciones en noticias, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Noticia"
        noticias_globales:
          description: "Tag: noticias_globales (DAT-NEWS). Noticias internacionales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Noticia"
        migrations:
          description: "Tag: migrations (DAT-LEGAL). Registros migratorios, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Migration"
        work_permits:
          description: "Tag: work_permits (DAT-LEGAL). Permisos de trabajo, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/WorkPermit"

    NaturalPersonDetail:
      title: "Detalle de Persona Natural"
      type: object
      description: |
        Detalle de una entidad de tipo persona natural. Los campos base siempre se
        retornan y corresponden al tag `core_registro`, cubierto por `CHK-BIN`
        y también por `DAT-CORE`. Las propiedades de tags solo están presentes cuando el código
        de producto correspondiente se solicita mediante el parámetro `include`.

        Las personas naturales no soportan los siguientes tags: contacto,
        directores, suspension, representante_legal_identificado, customs_summary,
        is_itbm, last_itbm_date, rp_report_url.
      required: [id, panadata_id, sid, nombre]
      properties:
        id:
          type: integer
        panadata_id:
          type: integer
          description: Identificador público estable de la entidad (actualmente igual a id).
        sid:
          type: string
        nombre:
          type: string
          nullable: true
        cedula:
          type: string
          nullable: true
        # --- propiedades de tags (incluidas mediante códigos de producto) ---
        entity_events:
          description: "Tag: entity_events (DAT-CORE, DAT-HOOK). Eventos recientes de la entidad, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EntityEvent"
        organizaciones:
          description: "Tag: organizaciones (DAT-GOV). Membresías en organizaciones, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/OrganizationMembership"
        gacetas:
          description: "Tag: gacetas (DAT-GOV). Menciones en Gaceta Oficial, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Gaceta"
        documentos_contraloria:
          description: "Tag: documentos_contraloria (DAT-GOV). Documentos de la Contraloría, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/ContraloriaDoc"
        funcionario:
          description: "Tag: funcionario (DAT-GOV). Registros de planilla de funcionarios públicos, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Planilla"
        avisos:
          description: "Tag: avisos (DAT-BIZ). Avisos de operación, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/BusinessNotice"
        licencias:
          description: "Tag: licencias (DAT-BIZ). Licencias generales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/GeneralLicense"
        personal_licenses:
          description: "Tag: personal_licenses (DAT-BIZ). Licencias personales/profesionales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/PersonalLicense"
        company_licenses:
          description: "Tag: company_licenses (DAT-BIZ). Licencias de empresa, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/CompanyLicense"
        fideicomisos:
          description: "Tag: fideicomisos (DAT-BIZ). Fideicomisos, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Fideicomiso"
        marcas:
          description: "Tag: marcas (DAT-BIZ). Marcas registradas, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Marca"
        propiedades:
          description: "Tag: propiedades (DAT-ASSET). Propiedades horizontales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Propiedad"
        fincas:
          description: "Tag: fincas (DAT-ASSET). Fincas, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Finca"
        bienes_muebles:
          description: "Tag: bienes_muebles (DAT-ASSET). Bienes muebles, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/BienMueble"
        naves:
          description: "Tag: naves (DAT-ASSET). Naves, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Nave"
        importaciones:
          description: "Tag: importaciones (DAT-TRADE). Registros de importación, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Importacion"
        exportaciones:
          description: "Tag: exportaciones (DAT-TRADE). Registros de exportación, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Exportacion"
        imports_summary:
          description: "Tag: imports_summary (DAT-TRADE). Estadísticas agregadas de importación de datos derivados."
          type: object
          nullable: true
        exports_summary:
          description: "Tag: exports_summary (DAT-TRADE). Estadísticas agregadas de exportación de datos derivados."
          type: object
          nullable: true
        documentos_escaneados:
          description: "Tag: documentos_escaneados (DAT-DOC). Documentos escaneados, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/DocumentoEscaneado"
        documentos_digitales:
          description: "Tag: documentos_digitales (DAT-DOC). Documentos digitales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/DocumentoDigital"
        css_moroso_menciones:
          description: "Tag: css_moroso_menciones (DAT-RISK). Menciones como moroso de la CSS, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/CSSMorosoMencion"
        sanciones:
          description: "Tag: sanciones (DAT-RISK). Sanciones, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Sancion"
        idoneidades:
          description: "Tag: idoneidades (DAT-RISK). Idoneidades profesionales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Idoneidad"
        expedientes_judiciales:
          description: "Tag: expedientes_judiciales (DAT-RISK). Expedientes judiciales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/ExpedienteJudicial"
        licitaciones:
          description: "Tag: licitaciones (DAT-PROC). Licitaciones públicas, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Licitacion"
        noticias:
          description: "Tag: noticias (DAT-NEWS). Menciones en noticias, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Noticia"
        noticias_globales:
          description: "Tag: noticias_globales (DAT-NEWS). Noticias internacionales, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Noticia"
        migrations:
          description: "Tag: migrations (DAT-LEGAL). Registros migratorios, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Migration"
        work_permits:
          description: "Tag: work_permits (DAT-LEGAL). Permisos de trabajo, máximo 100."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/WorkPermit"

    # ------------------------------------------------------------------
    # Esquema de resultado de búsqueda
    # ------------------------------------------------------------------
    EntitySummary:
      title: "Resumen de Entidad"
      type: object
      required: [id, nombre, type]
      properties:
        id:
          type: integer
          description: Use este ID en `GET /v4/panama/entidades/{id}`. La respuesta de detalle también incluye `panadata_id`.
        nombre:
          type: string
          nullable: true
        ruc_no_dv:
          type: string
          nullable: true
        type:
          type: string
          description: Identificador del tipo de entidad (ej. "Organization", "NaturalPerson").

    # ------------------------------------------------------------------
    # Esquemas de elementos de tags
    # ------------------------------------------------------------------
    EntityEvent:
      title: "Evento de Entidad"
      type: object
      properties:
        id:
          type: integer
        asset_type:
          type: string
          nullable: true
        asset_id:
          type: integer
          nullable: true
        event_action:
          type: string
          nullable: true
        asset_snapshot:
          type: object
          nullable: true
        asset_event_date:
          type: string
          nullable: true
          description: Cadena de fecha (ISO 8601).

    OrganizationMembership:
      title: "Membresía en Organización"
      type: object
      properties:
        cargo:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
        organization_id:
          type: integer
          nullable: true
        activo:
          type: boolean
          nullable: true

    BusinessNotice:
      title: "Aviso de Operación"
      type: object
      properties:
        numero:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
        ruc:
          type: string
          nullable: true
        estatus:
          type: string
          nullable: true
        fecha_generacion:
          type: string
          nullable: true

    GeneralLicense:
      title: "Licencia General"
      type: object
      properties:
        id:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
        activo:
          type: boolean
          nullable: true

    PersonalLicense:
      title: "Licencia Personal"
      type: object
      properties:
        id:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
        idoneidad:
          type: string
          nullable: true
        activo:
          type: boolean
          nullable: true

    CompanyLicense:
      title: "Licencia de Empresa"
      type: object
      properties:
        id:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true

    Propiedad:
      title: "Propiedad"
      type: object
      properties:
        id:
          type: integer
        folio:
          type: string
          nullable: true
        ficha:
          type: string
          nullable: true
        edificio:
          type: string
          nullable: true
        fecha_inscripcion:
          type: string
          nullable: true
        hipotecas:
          description: Hipotecas asociadas a la propiedad.
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/RealEstateElemento"
        compraventas:
          description: Compraventas asociadas a la propiedad.
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/RealEstateElemento"
        last_hipoteca:
          description: Última hipoteca registrada.
          type: object
          nullable: true
        last_compraventa:
          description: Última compraventa registrada.
          type: object
          nullable: true
        record_events:
          description: Eventos del registro asociados a la propiedad.
          type: array
          nullable: true
          items:
            type: object

    Finca:
      title: "Finca"
      type: object
      properties:
        id:
          type: integer
        folio:
          type: string
          nullable: true
        ficha:
          type: string
          nullable: true
        fecha_inscripcion:
          type: string
          nullable: true
        hipotecas:
          description: Hipotecas asociadas a la finca.
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/RealEstateElemento"
        compraventas:
          description: Compraventas asociadas a la finca.
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/RealEstateElemento"
        last_hipoteca:
          description: Última hipoteca registrada.
          type: object
          nullable: true
        last_compraventa:
          description: Última compraventa registrada.
          type: object
          nullable: true
        record_events:
          description: Eventos del registro asociados a la finca.
          type: array
          nullable: true
          items:
            type: object

    BienMueble:
      title: "Bien Mueble"
      type: object
      properties:
        id:
          type: integer
        folio:
          type: string
          nullable: true
        ficha:
          type: string
          nullable: true
        fecha_inscripcion:
          type: string
          nullable: true
        propietario_panadata_string:
          description: Nombre del propietario en formato Panadata.
          type: string
          nullable: true

    Nave:
      title: "Nave"
      type: object
      properties:
        id:
          type: integer
        nombre:
          type: string
          nullable: true
        ficha:
          type: string
          nullable: true
        fecha_registro:
          type: string
          nullable: true

    Importacion:
      title: "Importación"
      type: object
      properties:
        id:
          type: integer
        descripcion:
          type: string
          nullable: true
        fraccion_arancelaria:
          type: string
          nullable: true
        puerto_entrada:
          type: string
          nullable: true
        procedencia:
          type: string
          nullable: true
        fecha:
          type: string
          nullable: true
        valor_cif:
          type: number
          nullable: true

    Exportacion:
      title: "Exportación"
      type: object
      properties:
        id:
          type: integer
        descripcion:
          type: string
          nullable: true
        fraccion_arancelaria:
          type: string
          nullable: true
        puerto_salida:
          type: string
          nullable: true
        destino:
          type: string
          nullable: true
        fecha:
          type: string
          nullable: true
        valor_cif:
          type: number
          nullable: true

    DocumentoEscaneado:
      title: "Documento Escaneado"
      type: object
      properties:
        id:
          type: integer
        nombre:
          type: string
          nullable: true
        pdf_url:
          type: string
          nullable: true

    DocumentoDigital:
      title: "Documento Digital"
      type: object
      properties:
        id:
          type: integer
        entrada:
          type: string
          nullable: true
        detalle:
          type: string
          nullable: true
        fecha_ingreso:
          type: string
          nullable: true
        fecha_escritura:
          type: string
          nullable: true

    CSSMorosoMencion:
      title: "Mención CSS Moroso"
      type: object
      properties:
        id:
          type: integer
        titulo:
          type: string
          nullable: true
        fecha_publicacion:
          type: string
          nullable: true

    Sancion:
      title: "Sanción"
      type: object
      properties:
        id:
          type: integer
        nombre:
          type: string
          nullable: true
        tipo_sancion:
          type: string
          nullable: true

    Idoneidad:
      title: "Idoneidad"
      type: object
      properties:
        id:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
        idoneidad:
          type: string
          nullable: true

    ExpedienteJudicial:
      title: "Expediente Judicial"
      type: object
      properties:
        id:
          type: integer
        rue:
          type: string
          nullable: true
        partes:
          type: string
          nullable: true
        tipo_negocio:
          type: string
          nullable: true
        fecha_reparto:
          type: string
          nullable: true

    Licitacion:
      title: "Licitación"
      type: object
      properties:
        id:
          type: integer
        acto:
          type: string
          nullable: true
        descripcion:
          type: string
          nullable: true
        entidad:
          type: string
          nullable: true
        estado:
          type: string
          nullable: true
        fecha_publicacion:
          type: string
          nullable: true
        licitacion_url:
          type: string
          nullable: true
          description: Enlace directo a la página de licitación en PanamaCompra.
        documentos:
          type: array
          description: Documentos adjuntos con enlaces a PDF.
          items:
            type: object
            properties:
              nombre:
                type: string
                nullable: true
              pdf_url:
                type: string
                nullable: true

    # ------------------------------------------------------------------
    # Nuevos esquemas de componentes
    # ------------------------------------------------------------------
    Gaceta:
      title: "Gaceta"
      type: object
      description: Mención en la Gaceta Oficial.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        gaceta:
          type: string
          nullable: true
          description: Número o identificador de la gaceta.
        entidad:
          type: string
          nullable: true
          description: Entidad mencionada en la gaceta.
        titulo:
          type: string
          nullable: true
          description: Título de la publicación.
        descripcion:
          type: string
          nullable: true
          description: Descripción de la publicación.
        gaceta_url:
          type: string
          nullable: true
          description: Enlace al documento de la gaceta.
        pdf_url:
          type: string
          nullable: true
          description: Enlace al PDF de la gaceta.
        publicacion_id:
          type: string
          nullable: true
          description: Identificador de la publicación.
        fecha_publicacion:
          type: string
          nullable: true
          description: Fecha de publicación.
        fecha_redactacion:
          type: string
          nullable: true
          description: Fecha de redacción.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    Noticia:
      title: "Noticia"
      type: object
      description: Mención en noticias.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        titulo:
          type: string
          nullable: true
          description: Título de la noticia.
        fuente:
          type: string
          nullable: true
          description: Fuente de la noticia.
        url:
          type: string
          nullable: true
          description: URL de la noticia.
        fecha:
          type: string
          nullable: true
          description: Fecha de publicación.
        resumen:
          type: string
          nullable: true
          description: Resumen de la noticia.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    Fideicomiso:
      title: "Fideicomiso"
      type: object
      description: Fideicomiso inscrito en el Registro Público.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        ficha:
          type: string
          nullable: true
          description: Número de ficha del fideicomiso.
        folio:
          type: string
          nullable: true
          description: Número de folio del fideicomiso.
        fecha_inscripcion:
          type: string
          nullable: true
          description: Fecha de inscripción.
        rol:
          type: string
          nullable: true
          description: Rol de la entidad en el fideicomiso.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    Migration:
      title: "Registro Migratorio"
      type: object
      description: Registro migratorio.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        numero_caso:
          type: string
          nullable: true
          description: Número de caso migratorio.
        nombre:
          type: string
          nullable: true
          description: Nombre del solicitante.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    WorkPermit:
      title: "Permiso de Trabajo"
      type: object
      description: Permiso de trabajo.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        numero_caso:
          type: string
          nullable: true
          description: Número de caso del permiso.
        nombre:
          type: string
          nullable: true
          description: Nombre del solicitante.
        nacionalidad:
          type: string
          nullable: true
          description: Nacionalidad del solicitante.
        numero_pasaporte:
          type: string
          nullable: true
          description: Número de pasaporte.
        empresa:
          type: string
          nullable: true
          description: Empresa asociada al permiso.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    ContraloriaDoc:
      title: "Documento de Contraloría"
      type: object
      description: Documento de la Contraloría General de la República.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        tramite:
          type: string
          nullable: true
          description: Tipo de trámite.
        documento:
          type: string
          nullable: true
          description: Tipo de documento.
        institucion:
          type: string
          nullable: true
          description: Institución asociada.
        favor:
          type: string
          nullable: true
          description: Beneficiario del documento.
        fecha_entrada:
          type: string
          nullable: true
          description: Fecha de entrada del documento.
        fecha_refrando:
          type: string
          nullable: true
          description: Fecha de refrendo.
        fecha_salida:
          type: string
          nullable: true
          description: Fecha de salida del documento.
        numero:
          type: string
          nullable: true
          description: Número del documento.
        scafid:
          type: string
          nullable: true
          description: Identificador SCAFID.
        monto:
          type: number
          nullable: true
          description: Monto del documento.
        estado:
          type: string
          nullable: true
          description: Estado del trámite.
        asunto:
          type: string
          nullable: true
          description: Asunto del documento.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    Marca:
      title: "Marca"
      type: object
      description: Marca registrada.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        solicitud:
          type: string
          nullable: true
          description: Número de solicitud.
        nombre:
          type: string
          nullable: true
          description: Nombre de la marca.
        abogado:
          type: string
          nullable: true
          description: Abogado representante.
        titulares:
          type: string
          nullable: true
          description: Titulares de la marca.
        registro:
          type: string
          nullable: true
          description: Número de registro.
        fecha_solicitud:
          type: string
          nullable: true
          description: Fecha de solicitud.
        fecha_registro:
          type: string
          nullable: true
          description: Fecha de registro.
        fecha_vencimiento:
          type: string
          nullable: true
          description: Fecha de vencimiento.
        estado:
          type: string
          nullable: true
          description: Estado de la marca.
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    Planilla:
      title: "Planilla"
      type: object
      description: Registro de planilla de funcionario público.
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
          description: Nombre del funcionario.
        cedula:
          type: string
          nullable: true
          description: Cédula del funcionario.
        institucion:
          type: string
          nullable: true
          description: Institución donde labora.
        cargo:
          type: string
          nullable: true
          description: Cargo del funcionario.
        fecha_inicio:
          type: string
          nullable: true
          description: Fecha de inicio en el cargo.
        estado:
          type: string
          nullable: true
          description: Estado del registro (activo/inactivo).
        total:
          type: number
          nullable: true
          description: Total devengado.
        pep_score:
          type: number
          nullable: true
          description: Puntuación de Persona Expuesta Políticamente (PEP).
        source_updated_at:
          type: string
          nullable: true
          description: Marca de tiempo ISO 8601 de la última actualización de la fuente.

    RealEstateElemento:
      title: "Elemento Inmobiliario"
      type: object
      description: Elemento asociado a un bien inmueble (hipoteca o compraventa).
      properties:
        id:
          type: integer
        sid:
          type: string
          nullable: true
        nombre:
          type: string
          nullable: true
          description: Nombre o descripción del elemento.
        fecha:
          type: string
          nullable: true
          description: Fecha del registro.
        hipoteca:
          type: object
          nullable: true
          description: Datos de hipoteca asociada.
        compraventa:
          type: object
          nullable: true
          description: Datos de compraventa asociada.

    # ==================================================================
    # Esquema de solicitud de actualización
    # ==================================================================
    UpdateRequestStatus:
      title: "Estado de solicitud de actualización"
      type: object
      description: |
        Estado de una solicitud de actualización. Las 11 claves top-level
        están siempre presentes independiente del estado.
      required: [update_request_id, entity_id, jurisdiction, status, webhook_status, webhook_attempts, requested_codes, started_at, completed_at, result, error]
      properties:
        update_request_id:
          type: integer
        entity_id:
          type: integer
        jurisdiction:
          type: string
          enum: [panama, colombia, ecuador]
        status:
          type: string
          enum: [pending, completed, failed]
        webhook_status:
          type: string
          nullable: true
          enum: [pending, delivered, failed, null]
        webhook_attempts:
          type: integer
        requested_codes:
          type: array
          items:
            type: string
        started_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
        result:
          type: object
          nullable: true
          additionalProperties: true
        error:
          type: object
          nullable: true
          properties:
            message:
              type: string

    # ==================================================================
    # Esquemas Ecuador
    # ==================================================================
    WebhookEvent:
      type: object
      description: |
        Body que Panadata envía por POST a la URL de webhook del cliente cuando una
        Update Request se completa. Se documenta como schema (no como entrada
        `webhooks` de OpenAPI 3.1) porque esta especificación es OpenAPI 3.0.3.

        Headers del delivery:
        - `Content-Type: application/json`
        - `X-Panadata-Webhook-Signature: sha256={hex}` — HMAC-SHA256 sobre `{timestamp}.{body_bytes}`
        - `X-Panadata-Webhook-Timestamp: {unix_seconds}` — mismo valor en todos los reintentos

        Se intenta entregar hasta 3 veces con 5 s de timeout cada uno, sin backoff,
        en una ventana ≤ ~15 s. El mismo timestamp y la misma firma se envían en
        cada intento — deduplique usando `update_request_id`.
      required: [event, update_request_id, jurisdiction, data]
      properties:
        event:
          type: string
          enum: [update_request.completed]
        update_request_id: { type: integer, example: 16 }
        jurisdiction:      { type: string, example: panama }
        data:
          description: "Detalle de la entidad resuelta (mismo shape que la respuesta del GET de detalle para los códigos solicitados)."
          oneOf:
            - $ref: "#/components/schemas/OrganizationDetail"
            - $ref: "#/components/schemas/NaturalPersonDetail"

    OrganizationDetailEcuador:
      title: "Detalle de Organización (Ecuador)"
      type: object
      description: |
        Detalle de una organización ecuatoriana. Las propiedades de tags solo
        están presentes cuando el SKU correspondiente se solicita; cuando
        están presentes pero sin datos, las listas se retornan como `[]` y
        los objetos únicos como `null`. El tag `organizaciones` es
        persona-only y no aplica acá.
      required: [id, panadata_id, sid, nombre]
      properties:
        id:
          type: integer
        panadata_id:
          type: integer
        sid:
          type: string
        nombre:
          type: string
          nullable: true
        ruc:
          type: string
          nullable: true
        expediente:
          type: string
          nullable: true
        tipo_organizacion:
          type: string
          nullable: true
        situacion_legal:
          type: string
          nullable: true
        domicilio:
          type: string
          nullable: true
        ubicacion:
          type: object
          nullable: true
          properties:
            pais: { type: string, nullable: true }
            provincia: { type: string, nullable: true }
            canton: { type: string, nullable: true }
            ciudad: { type: string, nullable: true }
            barrio: { type: string, nullable: true }
        fecha_constitucion:
          type: string
          nullable: true
        fecha_ultima_actualizacion:
          type: string
          nullable: true
        objeto_social:
          type: string
          nullable: true
        capital_suscrito:
          type: string
          nullable: true
        capital_autorizado:
          type: string
          nullable: true
        actividades_economicas:
          type: array
          nullable: true
          items:
            type: object
            properties:
              codigo: { type: string, nullable: true }
              descripcion: { type: string, nullable: true }
        proveedor_estado:
          type: string
          nullable: true
        oficina_control:
          type: string
          nullable: true
        source_updated_at:
          type: string
          nullable: true
        contacto:
          description: "Tag: contacto (DAT-CORE)."
          type: object
          nullable: true
        entity_events:
          description: "Tag: entity_events (DAT-CORE)."
          type: array
          items:
            type: object
        directores:
          description: "Tag: directores (DAT-ALL)."
          type: array
          items:
            $ref: "#/components/schemas/EcuadorDirector"
        accionistas:
          description: "Tag: accionistas (DAT-ALL)."
          type: array
          items:
            $ref: "#/components/schemas/EcuadorAccionista"
        sri_reports:
          description: "Tag: sri_reports (DAT-ALL). Reporte fiscal del SRI (objeto único)."
          nullable: true
          $ref: "#/components/schemas/EcuadorSriReport"
        css_moroso_menciones:
          description: "Tag: css_moroso_menciones (DAT-ALL)."
          type: array
          items:
            $ref: "#/components/schemas/EcuadorDebtor"
        expedientes_judiciales:
          description: "Tag: expedientes_judiciales (DAT-ALL)."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EcuadorExpediente"
        denuncias:
          description: "Tag: denuncias (DAT-ALL). Denuncias en que la organización figura como sujeto (sospechoso, procesado, perjudicado, etc.)."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EcuadorDenuncia"
        licitaciones:
          description: "Tag: licitaciones (DAT-ALL)."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EcuadorLicitacion"
        noticias:
          description: "Tag: noticias (DAT-ALL)."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EcuadorNoticia"
        licencias:
          description: "Tag: licencias (DAT-ALL)."
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/EcuadorLicencia"
        documentos_digitales:
          description: "Tag: documentos_digitales (DAT-ALL). Documento kardex (objeto único)."
          nullable: true
          type: object
          properties:
            kardex_pdf_url:
              type: string

    EcuadorDirector:
      title: "Director (Ecuador)"
      type: object
      properties:
        ruc: { type: string, nullable: true }
        cargo: { type: string, nullable: true }
        fecha: { type: string, nullable: true }
        activo: { type: boolean, nullable: true }
        owner_id: { type: integer, nullable: true }

    EcuadorAccionista:
      title: "Accionista (Ecuador)"
      type: object
      properties:
        ruc: { type: string, nullable: true }
        activo: { type: boolean, nullable: true }
        owner_id: { type: integer, nullable: true }

    EcuadorSriReport:
      title: "Reporte SRI (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        ruc: { type: string, nullable: true }
        razon_social: { type: string, nullable: true }
        estado_contribuyente: { type: string, nullable: true }
        clase_contribuyente: { type: string, nullable: true }
        tipo_contribuyente: { type: string, nullable: true }
        actividades_economicas:
          type: array
          nullable: true
          items: { type: object }
        obligaciones:
          type: array
          nullable: true
          items: { type: object }
        representantes_legales:
          type: array
          nullable: true
          items: { type: object }
        establecimientos:
          type: array
          nullable: true
          items: { type: object }
        source_updated_at: { type: string, nullable: true }

    EcuadorDebtor:
      title: "Deudor IESS (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        ruc: { type: string, nullable: true }
        razon_social: { type: string, nullable: true }
        deudas:
          type: array
          nullable: true
          items: { type: object }
        source_updated_at: { type: string, nullable: true }

    EcuadorExpediente:
      title: "Expediente Judicial (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        numero_proceso: { type: string, nullable: true }
        tipo: { type: string, nullable: true }
        fecha_ingreso: { type: string, nullable: true }
        incidentes:
          type: array
          nullable: true
          items: { type: object }

    EcuadorDenuncia:
      title: "Denuncia (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        numero_denuncia: { type: string, nullable: true }
        fecha: { type: string, nullable: true }
        sujetos:
          type: array
          nullable: true
          items: { type: object }
        delitos:
          type: array
          nullable: true
          items: { type: object }

    EcuadorLicitacion:
      title: "Licitación (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        numero_proceso: { type: string, nullable: true }
        entidad: { type: string, nullable: true }
        descripcion: { type: string, nullable: true }
        estado: { type: string, nullable: true }
        objeto: { type: string, nullable: true }
        fecha_publicacion: { type: string, nullable: true }
        adjudicaciones:
          type: array
          nullable: true
          items: { type: object }
        propuestas:
          type: array
          nullable: true
          items: { type: object }

    EcuadorNoticia:
      title: "Noticia (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        sid: { type: string }
        titulo: { type: string, nullable: true }
        fuente: { type: string, nullable: true }
        url: { type: string, nullable: true }
        fecha: { type: string, nullable: true }
        resumen: { type: string, nullable: true }
        is_risky: { type: boolean, nullable: true }
        risk_score: { type: number, nullable: true }
        risk_category: { type: string, nullable: true }
        entities:
          type: array
          items: { type: object }

    EcuadorLicencia:
      title: "Licencia (Ecuador)"
      type: object
      properties:
        id: { type: integer }
        nombre_comercial: { type: string, nullable: true }
        razon_social: { type: string, nullable: true }
        titular: { type: string, nullable: true }
        tipo: { type: string, nullable: true }
        estado: { type: string, nullable: true }
        fecha: { type: string, nullable: true }
        actividad: { type: string, nullable: true }

    # ==================================================================
    # Esquemas Colombia
    # ==================================================================
    OrganizationDetailColombia:
      title: "Detalle de Organización (Colombia)"
      type: object
      description: |
        Detalle de una organización colombiana. El catálogo Colombia hoy solo
        incluye core_registro (cubierto por CHK-BIN y DAT-CORE).
      required: [id, panadata_id, sid]
      properties:
        id: { type: integer }
        panadata_id: { type: integer }
        sid: { type: string }
        nombre: { type: string, nullable: true }
        nit: { type: string, nullable: true }
        matricula: { type: string, nullable: true }
        detalle_id: { type: string, nullable: true }
        tipo_organizacion: { type: string, nullable: true }
        estado: { type: string, nullable: true }
        categoria: { type: string, nullable: true }
        estado_matricula: { type: string, nullable: true }
        numero_matricula: { type: string, nullable: true }
        fecha_matricula: { type: string, nullable: true }
        fecha_cancelacion: { type: string, nullable: true }
        fecha_vigencia: { type: string, nullable: true }
        fecha_ultima_actualizacion: { type: string, nullable: true }
        actividades_economicas:
          type: array
          nullable: true
          items: { type: object }
        camara_comercio: { type: string, nullable: true }
        identificacion: { type: string, nullable: true }
        sigla: { type: string, nullable: true }
        source_updated_at: { type: string, nullable: true }

    NaturalPersonDetailColombia:
      title: "Detalle de Persona Natural (Colombia)"
      type: object
      description: |
        Detalle de una persona natural colombiana. El catálogo Colombia hoy
        solo incluye core_registro.
      required: [id, panadata_id, sid]
      properties:
        id: { type: integer }
        panadata_id: { type: integer }
        sid: { type: string }
        nombre: { type: string, nullable: true }
        nit: { type: string, nullable: true }
        cedula: { type: string, nullable: true }
        tipo_organizacion: { type: string, nullable: true }
        fecha_ultima_actualizacion: { type: string, nullable: true }
        source_updated_at: { type: string, nullable: true }

    # ------------------------------------------------------------------
    # Esquema de error
    # ------------------------------------------------------------------
    GatewayUnauthorizedError:
      type: object
      required: [message]
      properties:
        message:
          type: string

    GatewayForbiddenError:
      type: object
      required: [Message]
      properties:
        Message:
          type: string

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: string
